xref: /titanic_50/usr/src/lib/libstmf/common/store.c (revision cb8a054b1ab30d5caa746e6c44f29d4c9d3071c1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <libscf.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <strings.h>
32 #include <libstmf.h>
33 #include <store.h>
34 #include <syslog.h>
35 #include <signal.h>
36 #include <pthread.h>
37 #include <libnvpair.h>
38 #include <limits.h>
39 #include <unistd.h>
40 
41 /*
42  * This file's functions are responsible for all store and retrieve operations
43  * against the STMF smf(5) database. The following shows the currently defined
44  * schema for the STMF database:
45  *
46  * Description of property groups for service: svc:/system/stmf
47  *
48  * Stability: Volatile
49  *
50  * 1. Property Group: host_groups
51  *        Properties: group_name-<N> where <N> is an unsigned integer
52  *                        type: ustring
53  *                        contains: group name
54  *                    group_name-<N>-member_list where <N> is an unsigned
55  *                            integer matching a group_name-<N> property.
56  *                        type: ustring
57  *                        contains: list of members
58  *
59  *        Description:
60  *             Contains the host group names as well as the host group members
61  *             for each host group.
62  *
63  * 2. Property Group: target_groups
64  *        Properties: group_name-<N> where <N> is an unsigned integer
65  *                        type: ustring
66  *                        contains: group name
67  *                    group_name-<N>-member_list where <N> is an unsigned
68  *                            integer matching a group_name-<N> property.
69  *                        type: ustring
70  *                        contains: list of members
71  *
72  *        Description:
73  *             Contains the target group names as well as the target group
74  *             members for each target group.
75  *
76  * 3. Property Group: lu-<GUID>
77  *                        where <GUID> is a 32 character hexadecimal string.
78  *        Properties: ve_cnt
79  *                        type: count
80  *                        contains: the number of current view entries
81  *                    view-entry-<N>-<GUID> where <N> is an unsigned integer
82  *                        type: ustring
83  *                        contains: nothing. Used as reference to the view
84  *                                  entry property group
85  *
86  *        Description:
87  *             Contains the references to each view entry. One lu-<GUID>
88  *             property group will exist for each logical unit with 1 or more
89  *             view entries.
90  *             Potentially can hold any other data that can be managed on a per
91  *             logical unit basis.
92  *
93  * 4. Property Group: view_entry-<N>-<GUID> (matches property in lu-<GUID>
94  *                    property group)
95  *        Properties: all_hosts
96  *                        type: boolean
97  *                        contains: when true, the value of host_group is
98  *                                  ignored
99  *                    all_targets
100  *                        type: boolean
101  *                        contains: when true, the value of target_group is
102  *                                  ignored
103  *                    host_group
104  *                        type: ustring
105  *                        contains: host group for logical unit mapping and
106  *                                  masking purposes
107  *                    target_group
108  *                        type: ustring
109  *                        contains: target group for logical unit mapping and
110  *                                  masking purposes
111  *                    lu_nbr
112  *                        type: opaque
113  *                        contains: the 8-byte SCSI logical unit number for
114  *                                  mapping and masking purposes
115  *        Description:
116  *             One "view_entry-<N>-<GUID>" property group will exist for each
117  *             view entry in the system. This property group name maps
118  *             directly to the "lu-<GUID>" property group with a matching
119  *             <GUID>.
120  *
121  * 5. Property Group: provider_data_pg_<provider-name>
122  *                        where <provider-name> is the name of the provider
123  *                           registered with stmf.
124  *        Properties: provider_data_prop-<N>
125  *                        where <N> is a sequential identifier for the data
126  *                           chunk.
127  *                        type: opaque
128  *                        contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes
129  *                                  of nvlist packed data.
130  *                    provider_data_count
131  *                        type: count
132  *                        contains: the number of provider data chunks
133  *                    provider_data_type
134  *                        type: integer
135  *                        contains: STMF_PORT_PROVIDER_TYPE or
136  *                                  STMF_LU_PROVIDER_TYPE
137  *
138  *        Description:
139  *             Holds the nvlist packed provider data set via
140  *             stmfSetProviderData and retrieved via stmfGetProviderData. Data
141  *             is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve,
142  *             these chunks are reassembled and unpacked.
143  *
144  */
145 
146 static int iPsInit(scf_handle_t **, scf_service_t **);
147 static int iPsCreateDeleteGroup(char *, char *, int);
148 static int iPsAddRemoveGroupMember(char *, char *, char *, int);
149 static int iPsGetGroupList(char *, stmfGroupList **);
150 static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **);
151 static int iPsAddViewEntry(char *, char *, stmfViewEntry *);
152 static int iPsAddRemoveLuViewEntry(char *, char *, int);
153 static int iPsGetViewEntry(char *, stmfViewEntry *);
154 static int iPsGetActualGroupName(char *, char *, char *);
155 static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
156 static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *,
157     int);
158 static int viewEntryCompare(const void *, const void *);
159 static int holdSignal(sigset_t *);
160 static int releaseSignal(sigset_t *);
161 static void sigHandler();
162 
163 static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER;
164 
165 sigset_t sigSet;
166 sigset_t signalsCaught;
167 
168 struct sigaction currentActionQuit;
169 struct sigaction currentActionTerm;
170 struct sigaction currentActionInt;
171 
172 boolean_t actionSet = B_FALSE;
173 
174 /*
175  * Version info for the SMF schema
176  */
177 #define	STMF_SMF_VERSION    1
178 
179 /*
180  * Note: Do not change these property names and size values.
181  * They represent fields in the persistent config and once modified
182  * will have a nasty side effect of invalidating the existing store.
183  * If you do need to change them, you'll need to use the versioning above
184  * to retain backward compatiblity with the previous configuration schema.
185  */
186 
187 /* BEGIN STORE PROPERTY DEFINITIONS */
188 /*
189  * Property Group Names and prefixes
190  */
191 #define	STMF_HOST_GROUPS	"host_groups"
192 #define	STMF_TARGET_GROUPS	"target_groups"
193 #define	STMF_VE_PREFIX		"view_entry"
194 #define	STMF_LU_PREFIX		"lu"
195 #define	STMF_DATA_GROUP		"stmf_data"
196 
197 /*
198  * Property names and prefix for logical unit property group
199  */
200 #define	STMF_VE_CNT		"ve_cnt"
201 #define	STMF_GROUP_PREFIX	"group_name"
202 #define	STMF_MEMBER_LIST_SUFFIX	"member_list"
203 #define	STMF_VERSION_NAME	"version_name"
204 #define	STMF_PERSIST_TYPE	"persist_method"
205 
206 /*
207  * Property names for view entry
208  */
209 #define	STMF_VE_ALLHOSTS	    "all_hosts"
210 #define	STMF_VE_HOSTGROUP	    "host_group"
211 #define	STMF_VE_ALLTARGETS	    "all_targets"
212 #define	STMF_VE_TARGETGROUP	    "target_group"
213 #define	STMF_VE_LUNBR		    "lu_nbr"
214 
215 /* Property group suffix for provider data */
216 #define	STMF_PROVIDER_DATA_PREFIX "provider_data_pg_"
217 #define	STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop"
218 #define	STMF_PROVIDER_DATA_PROP_NAME_SIZE 256
219 #define	STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
220 #define	STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
221 #define	STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"
222 
223 
224 #define	STMF_SMF_READ_ATTR	"solaris.smf.read.stmf"
225 
226 #define	STMF_PS_PERSIST_NONE	"none"
227 #define	STMF_PS_PERSIST_SMF	"smf"
228 #define	STMF_PROVIDER_DATA_PROP_SIZE 4000
229 /* END STORE PROPERTY DEFINITIONS */
230 
231 /* service name */
232 #define	STMF_SERVICE	"system/stmf"
233 
234 /* limits and flag values */
235 #define	GROUP_MEMBER_ALLOC 100
236 #define	VIEW_ENTRY_STRUCT_CNT 6
237 #define	VIEW_ENTRY_PG_SIZE 256
238 #define	LOGICAL_UNIT_PG_SIZE 256
239 #define	VIEW_ENTRY_MAX UINT32_MAX
240 #define	GROUP_MAX UINT64_MAX
241 #define	ADD 0
242 #define	REMOVE 1
243 #define	GET 0
244 #define	SET 1
245 
246 /*
247  * sigHandler
248  *
249  * Catch the signal and set the global signalsCaught to the signal received
250  *
251  * signalsCaught will be used by releaseSignal to raise this signal when
252  * we're done processing our critical code.
253  *
254  */
255 static void
256 sigHandler(int sig)
257 {
258 	(void) sigaddset(&signalsCaught, sig);
259 }
260 
261 /*
262  * iPsAddRemoveGroupMember
263  *
264  * Add or remove a member for a given group
265  *
266  * pgName - Property group name
267  * groupName - group name to which the member is added/removed
268  * memberName - member to be added/removed
269  * addRemoveFlag - ADD/REMOVE
270  *
271  * returns:
272  *  STMF_PS_SUCCESS on success
273  *  STMF_PS_ERROR_* on failure
274  */
275 static int
276 iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName,
277 int addRemoveFlag)
278 {
279 	scf_handle_t *handle = NULL;
280 	scf_service_t *svc = NULL;
281 	scf_propertygroup_t *pg = NULL;
282 	scf_property_t *prop = NULL;
283 	scf_value_t *valueLookup = NULL;
284 	scf_value_t **valueSet = NULL;
285 	scf_iter_t *valueIter = NULL;
286 	scf_transaction_t *tran = NULL;
287 	scf_transaction_entry_t *entry = NULL;
288 	int i = 0;
289 	int lastAlloc;
290 	int valueArraySize = 0;
291 	int ret = STMF_PS_SUCCESS;
292 	char buf[STMF_IDENT_LENGTH];
293 	int commitRet;
294 	boolean_t found = B_FALSE;
295 
296 	assert(pgName != NULL && groupName != NULL && memberName != NULL);
297 
298 	/*
299 	 * Init the service handle
300 	 */
301 	ret = iPsInit(&handle, &svc);
302 	if (ret != STMF_PS_SUCCESS) {
303 		goto out;
304 	}
305 
306 	/*
307 	 * Allocate scf resources
308 	 */
309 	if (((pg = scf_pg_create(handle)) == NULL) ||
310 	    ((tran = scf_transaction_create(handle)) == NULL) ||
311 	    ((entry = scf_entry_create(handle)) == NULL) ||
312 	    ((prop = scf_property_create(handle)) == NULL) ||
313 	    ((valueIter = scf_iter_create(handle)) == NULL)) {
314 		syslog(LOG_ERR, "scf alloc resource failed - %s",
315 		    scf_strerror(scf_error()));
316 		ret = STMF_PS_ERROR;
317 		goto out;
318 	}
319 
320 	/*
321 	 * Get the service property group handle
322 	 */
323 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
324 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
325 			ret = STMF_PS_ERROR_NOT_FOUND;
326 		} else {
327 			ret = STMF_PS_ERROR;
328 		}
329 		syslog(LOG_ERR, "get pg %s failed - %s",
330 		    pgName, scf_strerror(scf_error()));
331 
332 		goto out;
333 	}
334 
335 	/*
336 	 * Begin the transaction
337 	 */
338 	if (scf_transaction_start(tran, pg) == -1) {
339 		syslog(LOG_ERR, "start transaction for %s failed - %s",
340 		    pgName, scf_strerror(scf_error()));
341 		ret = STMF_PS_ERROR;
342 		goto out;
343 	}
344 
345 	/*
346 	 * We're changing an existing property by adding a propval
347 	 * There are no add semantics in libscf for a property value. We'll
348 	 * need to read in the current properties and apply them all to the
349 	 * set and then add the one we were asked to add or omit the one
350 	 * we were asked to remove.
351 	 */
352 	if (scf_transaction_property_change(tran, entry, groupName,
353 	    SCF_TYPE_USTRING) == -1) {
354 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
355 			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
356 		} else {
357 			ret = STMF_PS_ERROR;
358 			syslog(LOG_ERR, "tran property change %s/%s "
359 			    "failed - %s", pgName, groupName,
360 			    scf_strerror(scf_error()));
361 		}
362 		goto out;
363 	}
364 
365 	/*
366 	 * Get the property handle
367 	 */
368 	if (scf_pg_get_property(pg, groupName, prop) == -1) {
369 		syslog(LOG_ERR, "get property %s/%s failed - %s",
370 		    pgName, groupName, scf_strerror(scf_error()));
371 		ret = STMF_PS_ERROR;
372 		goto out;
373 	}
374 
375 	/*
376 	 * Value lookup is used to lookup the existing values
377 	 */
378 	valueLookup = scf_value_create(handle);
379 	if (valueLookup == NULL) {
380 		syslog(LOG_ERR, "scf value alloc for %s failed - %s",
381 		    pgName, scf_strerror(scf_error()));
382 		ret = STMF_PS_ERROR;
383 		goto out;
384 	}
385 
386 	/*
387 	 * valueIter is the iterator handle, create the resource
388 	 */
389 	if (scf_iter_property_values(valueIter, prop) == -1) {
390 		syslog(LOG_ERR, "iter values for %s/%s failed - %s",
391 		    pgName, groupName, scf_strerror(scf_error()));
392 		ret = STMF_PS_ERROR;
393 		goto out;
394 	}
395 
396 	/*
397 	 * Allocate value resource pointers.
398 	 * We need a value resource for each value as value pointers passed
399 	 * to libscf cannot be destroyed until the commit or destroy on the
400 	 * transaction is done.
401 	 *
402 	 * We're using GROUP_MEMBER_ALLOC initially. If it's not large
403 	 * enough, we'll realloc on the fly
404 	 */
405 	valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
406 	    * (lastAlloc = GROUP_MEMBER_ALLOC));
407 	if (valueSet == NULL) {
408 		ret = STMF_PS_ERROR_NOMEM;
409 		goto out;
410 	}
411 
412 	/*
413 	 * Iterate through the existing values
414 	 */
415 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
416 		bzero(buf, sizeof (buf));
417 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
418 			syslog(LOG_ERR, "iter %s/%s value failed - %s",
419 			    pgName, groupName, scf_strerror(scf_error()));
420 			ret = STMF_PS_ERROR;
421 			break;
422 		}
423 
424 		/*
425 		 * Check for existing
426 		 * If we're adding, it's an error
427 		 * If we're removing, we skip it and simply not
428 		 * add it to the set. Subtraction by omission.
429 		 */
430 		if ((strlen(buf) == strlen(memberName)) &&
431 		    bcmp(buf, memberName, strlen(buf)) == 0) {
432 			if (addRemoveFlag == ADD) {
433 				ret = STMF_PS_ERROR_EXISTS;
434 				break;
435 			} else {
436 				found = B_TRUE;
437 				continue;
438 			}
439 		}
440 
441 		/*
442 		 * Create the value resource for this iteration
443 		 */
444 		valueSet[i] = scf_value_create(handle);
445 		if (valueSet[i] == NULL) {
446 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
447 			    pgName, scf_strerror(scf_error()));
448 			ret = STMF_PS_ERROR;
449 			break;
450 		}
451 
452 		/*
453 		 * Set the value
454 		 */
455 		if (scf_value_set_ustring(valueSet[i], buf) == -1) {
456 			syslog(LOG_ERR, "set value for %s/%s failed - %s",
457 			    pgName, groupName, scf_strerror(scf_error()));
458 			ret = STMF_PS_ERROR;
459 			break;
460 		}
461 
462 		/*
463 		 * Now add the value
464 		 */
465 		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
466 			syslog(LOG_ERR, "add value for %s/%s failed - %s",
467 			    pgName, groupName, scf_strerror(scf_error()));
468 			ret = STMF_PS_ERROR;
469 			break;
470 		}
471 
472 		i++;
473 
474 		/*
475 		 * realloc if we've hit the previous alloc size
476 		 */
477 		if (i >= lastAlloc) {
478 			lastAlloc += GROUP_MEMBER_ALLOC;
479 			valueSet = realloc(valueSet,
480 			    sizeof (*valueSet) * lastAlloc);
481 			if (valueSet == NULL) {
482 				ret = STMF_PS_ERROR;
483 				break;
484 			}
485 		}
486 	}
487 
488 	/*
489 	 * set valueArraySize to final allocated length
490 	 * so we can use it to destroy the resources correctly
491 	 */
492 	valueArraySize = i;
493 
494 	if (!found && (addRemoveFlag == REMOVE)) {
495 		ret = STMF_PS_ERROR_MEMBER_NOT_FOUND;
496 	}
497 
498 	if (ret != STMF_PS_SUCCESS) {
499 		goto out;
500 	}
501 
502 	/*
503 	 * If we're adding, we have one more step. Add the member to the
504 	 * propval list
505 	 */
506 	if (addRemoveFlag == ADD) {
507 		/*
508 		 * Now create the new entry
509 		 */
510 		valueSet[i] = scf_value_create(handle);
511 		if (valueSet[i] == NULL) {
512 			syslog(LOG_ERR, "scf value alloc for %s/%s failed - %s",
513 			    pgName, groupName, scf_strerror(scf_error()));
514 			ret = STMF_PS_ERROR;
515 			goto out;
516 		} else {
517 			valueArraySize++;
518 		}
519 
520 		/*
521 		 * Set the new member name
522 		 */
523 		if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
524 			syslog(LOG_ERR, "set value for %s/%s failed - %s",
525 			    pgName, groupName, scf_strerror(scf_error()));
526 			ret = STMF_PS_ERROR;
527 			goto out;
528 		}
529 
530 		/*
531 		 * Add the new member
532 		 */
533 		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
534 			syslog(LOG_ERR, "add value for %s/%s failed - %s",
535 			    pgName, groupName, scf_strerror(scf_error()));
536 			ret = STMF_PS_ERROR;
537 			goto out;
538 		}
539 	}
540 
541 	/*
542 	 * Yes, we're finally done. We actually added or removed one entry
543 	 * from the list.
544 	 * Woohoo!
545 	 */
546 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
547 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
548 		    pgName, scf_strerror(scf_error()));
549 		if (commitRet == 0) {
550 			ret = STMF_PS_ERROR_BUSY;
551 		} else {
552 			ret = STMF_PS_ERROR;
553 		}
554 		goto out;
555 	}
556 
557 out:
558 	/*
559 	 * Free resources
560 	 */
561 	if (handle != NULL) {
562 		scf_handle_destroy(handle);
563 	}
564 	if (svc != NULL) {
565 		scf_service_destroy(svc);
566 	}
567 	if (pg != NULL) {
568 		scf_pg_destroy(pg);
569 	}
570 	if (tran != NULL) {
571 		scf_transaction_destroy(tran);
572 	}
573 	if (entry != NULL) {
574 		scf_entry_destroy(entry);
575 	}
576 	if (prop != NULL) {
577 		scf_property_destroy(prop);
578 	}
579 	if (valueLookup != NULL) {
580 		scf_value_destroy(valueLookup);
581 	}
582 	if (valueIter != NULL) {
583 		scf_iter_destroy(valueIter);
584 	}
585 
586 	/*
587 	 * Free valueSet scf resources
588 	 */
589 	if (valueArraySize > 0) {
590 		for (i = 0; i < valueArraySize; i++) {
591 			scf_value_destroy(valueSet[i]);
592 		}
593 	}
594 	/*
595 	 * Now free the pointer array to the resources
596 	 */
597 	if (valueSet != NULL) {
598 		free(valueSet);
599 	}
600 
601 	return (ret);
602 }
603 
604 /*
605  * iPsAddRemoveLuViewEntry
606  *
607  * Adds or removes a view entry name property for a given logical unit
608  * property group. There is one logical unit property group for every logical
609  * unit that has one or more associated view entries.
610  *
611  * luPgName - Property group name of logical unit
612  * viewEntryPgName - Property group name of view entry
613  * addRemoveFlag - ADD_VE/REMOVE_VE
614  *
615  * returns:
616  *  STMF_PS_SUCCESS on success
617  *  STMF_PS_ERROR_* on failure
618  */
619 static int
620 iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName,
621     int addRemoveFlag)
622 {
623 	scf_handle_t	*handle = NULL;
624 	scf_service_t	*svc = NULL;
625 	scf_propertygroup_t	*pg = NULL;
626 	scf_property_t	*prop = NULL;
627 	scf_value_t	*value = NULL;
628 	scf_transaction_t   *tran = NULL;
629 	scf_transaction_entry_t *entry = NULL;
630 	scf_transaction_entry_t *entryVeName = NULL;
631 	boolean_t createVeCnt = B_FALSE;
632 	uint64_t veCnt = 0;
633 	int ret = STMF_PS_SUCCESS;
634 	int commitRet;
635 
636 	assert(luPgName != NULL || viewEntryPgName != NULL);
637 	assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE));
638 
639 	/*
640 	 * Init the service handle
641 	 */
642 	ret = iPsInit(&handle, &svc);
643 	if (ret != STMF_PS_SUCCESS) {
644 		goto out;
645 	}
646 
647 	/*
648 	 * Allocate scf resources
649 	 */
650 	if (((pg = scf_pg_create(handle)) == NULL) ||
651 	    ((tran = scf_transaction_create(handle)) == NULL) ||
652 	    ((entry = scf_entry_create(handle)) == NULL) ||
653 	    ((prop = scf_property_create(handle)) == NULL) ||
654 	    ((value = scf_value_create(handle)) == NULL)) {
655 		syslog(LOG_ERR, "scf alloc resource failed - %s",
656 		    scf_strerror(scf_error()));
657 		ret = STMF_PS_ERROR;
658 		goto out;
659 	}
660 
661 	/* get the LU property group */
662 	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
663 		if (scf_error() == SCF_ERROR_NOT_FOUND &&
664 		    addRemoveFlag == ADD) {
665 			/* if it doesn't exist, create it */
666 			if (scf_service_add_pg(svc, luPgName,
667 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
668 				syslog(LOG_ERR, "add pg %s failed - %s",
669 				    luPgName, scf_strerror(scf_error()));
670 				ret = STMF_PS_ERROR;
671 			} else {
672 				/* we need to create the VE_CNT property */
673 				createVeCnt = B_TRUE;
674 				ret = STMF_PS_SUCCESS;
675 			}
676 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
677 			ret = STMF_PS_ERROR_NOT_FOUND;
678 		} else {
679 			syslog(LOG_ERR, "get lu pg %s failed - %s",
680 			    luPgName, scf_strerror(scf_error()));
681 			ret = STMF_PS_ERROR;
682 		}
683 		if (ret != STMF_PS_SUCCESS) {
684 			goto out;
685 		}
686 	}
687 
688 
689 	/*
690 	 * Begin the transaction
691 	 */
692 	if (scf_transaction_start(tran, pg) == -1) {
693 		syslog(LOG_ERR, "start transaction for %s failed - %s",
694 		    luPgName, scf_strerror(scf_error()));
695 		ret = STMF_PS_ERROR;
696 		goto out;
697 	}
698 
699 
700 	if (createVeCnt) {
701 		/*
702 		 * Create the STMF_VE_CNT property. This will keep the current
703 		 * total view entries for this logical unit.
704 		 */
705 		if (scf_transaction_property_new(tran, entry, STMF_VE_CNT,
706 		    SCF_TYPE_COUNT) == -1) {
707 			if (scf_error() == SCF_ERROR_EXISTS) {
708 				ret = STMF_PS_ERROR_EXISTS;
709 			} else {
710 				syslog(LOG_ERR,
711 				    "transaction property new %s/%s "
712 				    "failed - %s", luPgName, STMF_VE_CNT,
713 				    scf_strerror(scf_error()));
714 				ret = STMF_PS_ERROR;
715 			}
716 			goto out;
717 		}
718 	} else {
719 		/*
720 		 * The STMF_VE_CNT property already exists. Just update
721 		 * it.
722 		 */
723 		if (scf_transaction_property_change(tran, entry,
724 		    STMF_VE_CNT, SCF_TYPE_COUNT) == -1) {
725 			syslog(LOG_ERR, "transaction property %s/%s change "
726 			    "failed - %s", luPgName, STMF_VE_CNT,
727 			    scf_strerror(scf_error()));
728 			ret = STMF_PS_ERROR;
729 			goto out;
730 		}
731 
732 		/*
733 		 * Get the STMF_VE_CNT property
734 		 */
735 		if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
736 			syslog(LOG_ERR, "get property %s/%s failed - %s",
737 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
738 			ret = STMF_PS_ERROR;
739 			goto out;
740 		}
741 
742 		/*
743 		 * Get the STMF_VE_CNT value
744 		 */
745 		if (scf_property_get_value(prop, value) == -1) {
746 			syslog(LOG_ERR, "get property %s/%s value failed - %s",
747 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
748 			ret = STMF_PS_ERROR;
749 			goto out;
750 		}
751 
752 		/*
753 		 * Now get the actual value from the value handle
754 		 */
755 		if (scf_value_get_count(value, &veCnt) == -1) {
756 			syslog(LOG_ERR, "get count value %s/%s failed - %s",
757 			    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
758 			ret = STMF_PS_ERROR;
759 			goto out;
760 		}
761 
762 		/*
763 		 * Reset the value resource as it is used below
764 		 */
765 		scf_value_reset(value);
766 	}
767 
768 	if (addRemoveFlag == ADD) {
769 		veCnt++;
770 	} else {
771 		/* Check if this is the last one being removed */
772 		if (veCnt == 1) {
773 			/*
774 			 * Delete the pg and get out if this is the last
775 			 * view entry
776 			 */
777 			if (scf_pg_delete(pg) == -1) {
778 				syslog(LOG_ERR, "delete pg %s failed - %s",
779 				    luPgName, scf_strerror(scf_error()));
780 
781 				ret = STMF_PS_ERROR;
782 			}
783 			goto out;
784 		} else {
785 			veCnt--;
786 		}
787 	}
788 
789 
790 	/*
791 	 * Set the view entry count
792 	 */
793 	scf_value_set_count(value, veCnt);
794 
795 	/*
796 	 * Add the value to the transaction entry
797 	 */
798 	if (scf_entry_add_value(entry, value) == -1) {
799 		syslog(LOG_ERR, "add value %s/%s failed - %s",
800 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
801 		ret = STMF_PS_ERROR;
802 		goto out;
803 	}
804 
805 	/*
806 	 * Create a transaction entry resource for the view entry name
807 	 */
808 	entryVeName = scf_entry_create(handle);
809 	if (entryVeName == NULL) {
810 		syslog(LOG_ERR, "scf transaction entry alloc %s/%s failed - %s",
811 		    luPgName, viewEntryPgName, scf_strerror(scf_error()));
812 		ret = STMF_PS_ERROR;
813 		goto out;
814 	}
815 
816 	if (addRemoveFlag == ADD) {
817 		/*
818 		 * If adding, create a property with the view entry name
819 		 */
820 		if (scf_transaction_property_new(tran, entryVeName,
821 		    viewEntryPgName, SCF_TYPE_USTRING) == -1) {
822 			if (scf_error() == SCF_ERROR_EXISTS) {
823 				ret = STMF_PS_ERROR_EXISTS;
824 			} else {
825 				syslog(LOG_ERR,
826 				    "transaction property new %s/%s "
827 				    "failed - %s", luPgName, viewEntryPgName,
828 				    scf_strerror(scf_error()));
829 				ret = STMF_PS_ERROR;
830 			}
831 			goto out;
832 		}
833 	} else {
834 		/*
835 		 * If removing, delete the existing property with the view
836 		 * entry name
837 		 */
838 		if (scf_transaction_property_delete(tran, entryVeName,
839 		    viewEntryPgName) == -1) {
840 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
841 				ret = STMF_PS_ERROR_NOT_FOUND;
842 			} else {
843 				syslog(LOG_ERR,
844 				    "transaction property delete %s/%s "
845 				    "failed - %s", luPgName, viewEntryPgName,
846 				    scf_strerror(scf_error()));
847 				ret = STMF_PS_ERROR;
848 			}
849 			goto out;
850 		}
851 	}
852 
853 	/*
854 	 * Commit property transaction
855 	 */
856 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
857 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
858 		    luPgName, scf_strerror(scf_error()));
859 		if (commitRet == 0) {
860 			ret = STMF_PS_ERROR_BUSY;
861 		} else {
862 			ret = STMF_PS_ERROR;
863 		}
864 		goto out;
865 	}
866 
867 out:
868 	/*
869 	 * Free resources
870 	 */
871 	if (handle != NULL) {
872 		scf_handle_destroy(handle);
873 	}
874 	if (svc != NULL) {
875 		scf_service_destroy(svc);
876 	}
877 	if (pg != NULL) {
878 		scf_pg_destroy(pg);
879 	}
880 	if (tran != NULL) {
881 		scf_transaction_destroy(tran);
882 	}
883 	if (entry != NULL) {
884 		scf_entry_destroy(entry);
885 	}
886 	if (entryVeName != NULL) {
887 		scf_entry_destroy(entryVeName);
888 	}
889 	if (prop != NULL) {
890 		scf_property_destroy(prop);
891 	}
892 	if (value != NULL) {
893 		scf_value_destroy(value);
894 	}
895 
896 	return (ret);
897 }
898 
899 /*
900  * iPsAddViewEntry
901  *
902  * Add a view entry property group and optionally, a logical unit property
903  * group if it does not exist.
904  *
905  * luName - ascii hexadecimal logical unit identifier
906  * viewEntryName - name of view entry (VIEW_ENTRY_nn)
907  * viewEntry - pointer to stmfViewEntry structure
908  */
909 static int
910 iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry)
911 {
912 	scf_handle_t	*handle = NULL;
913 	scf_service_t	*svc = NULL;
914 	scf_propertygroup_t	*pg = NULL;
915 	scf_value_t	*value[VIEW_ENTRY_STRUCT_CNT];
916 	scf_transaction_t   *tran = NULL;
917 	scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT];
918 	int i = 0;
919 	int j = 0;
920 	int ret;
921 	uint8_t scfBool;
922 	boolean_t createdVePg = B_FALSE;
923 	int backoutRet;
924 	int commitRet;
925 
926 	assert(luPgName != NULL || viewEntryPgName != NULL ||
927 	    viewEntry == NULL);
928 
929 	bzero(value, sizeof (value));
930 	bzero(entry, sizeof (entry));
931 
932 	/*
933 	 * Init the service handle
934 	 */
935 	ret = iPsInit(&handle, &svc);
936 	if (ret != STMF_PS_SUCCESS) {
937 		goto out;
938 	}
939 
940 	/*
941 	 * Allocate scf resources
942 	 */
943 	if (((pg = scf_pg_create(handle)) == NULL) ||
944 	    ((tran = scf_transaction_create(handle)) == NULL)) {
945 		syslog(LOG_ERR, "scf alloc resource failed - %s",
946 		    scf_strerror(scf_error()));
947 		ret = STMF_PS_ERROR;
948 		goto out;
949 	}
950 
951 	/*
952 	 * allocate value and entry resources for scf
953 	 */
954 	for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) {
955 		if (((value[i] = scf_value_create(handle)) == NULL) ||
956 		    ((entry[i] = scf_entry_create(handle)) == NULL)) {
957 			syslog(LOG_ERR, "scf alloc resource failed - %s",
958 			    scf_strerror(scf_error()));
959 			ret = STMF_PS_ERROR;
960 			goto out;
961 		}
962 	}
963 
964 	i = 0;
965 
966 	/*
967 	 * Create the View Entry property group
968 	 */
969 	if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION,
970 	    0, pg) == -1) {
971 		if (scf_error() == SCF_ERROR_EXISTS) {
972 			ret = STMF_PS_ERROR_EXISTS;
973 		} else {
974 			syslog(LOG_ERR, "add pg %s failed - %s",
975 			    viewEntryPgName, scf_strerror(scf_error()));
976 			ret = STMF_PS_ERROR;
977 		}
978 		goto out;
979 	}
980 
981 	createdVePg = B_TRUE;
982 
983 	/*
984 	 * Add the view entry as properties on the view entry group
985 	 */
986 
987 	/*
988 	 * Begin property update transaction
989 	 */
990 	if (scf_transaction_start(tran, pg) == -1) {
991 		syslog(LOG_ERR, "start transaction for add %s failed - %s",
992 		    viewEntryPgName, scf_strerror(scf_error()));
993 		ret = STMF_PS_ERROR;
994 		goto out;
995 	}
996 
997 	/*
998 	 * Add allHosts property
999 	 */
1000 	if (scf_transaction_property_new(tran, entry[i],
1001 	    STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) {
1002 		if (scf_error() == SCF_ERROR_EXISTS) {
1003 			ret = STMF_PS_ERROR_EXISTS;
1004 		} else {
1005 			syslog(LOG_ERR, "transaction property new %s/%s "
1006 			    "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS,
1007 			    scf_strerror(scf_error()));
1008 			ret = STMF_PS_ERROR;
1009 		}
1010 		goto out;
1011 	}
1012 
1013 	/* Set the allHosts value */
1014 	scfBool = viewEntry->allHosts;
1015 	scf_value_set_boolean(value[i], scfBool);
1016 
1017 	/*
1018 	 * Add the allHosts value to the transaction
1019 	 */
1020 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1021 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1022 		    viewEntryPgName, STMF_VE_ALLHOSTS,
1023 		    scf_strerror(scf_error()));
1024 		ret = STMF_PS_ERROR;
1025 		goto out;
1026 	}
1027 
1028 	i++;
1029 
1030 	/*
1031 	 * Create hostGroup property
1032 	 */
1033 	if (scf_transaction_property_new(tran, entry[i],
1034 	    STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) {
1035 		if (scf_error() == SCF_ERROR_EXISTS) {
1036 			ret = STMF_PS_ERROR_EXISTS;
1037 		} else {
1038 			syslog(LOG_ERR, "transaction property new %s/%s "
1039 			    "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP,
1040 			    scf_strerror(scf_error()));
1041 			ret = STMF_PS_ERROR;
1042 		}
1043 		goto out;
1044 	}
1045 
1046 	/*
1047 	 * Set the value for hostGroup
1048 	 */
1049 	if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) {
1050 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1051 		    viewEntryPgName, STMF_VE_HOSTGROUP,
1052 		    scf_strerror(scf_error()));
1053 		ret = STMF_PS_ERROR;
1054 		goto out;
1055 	}
1056 
1057 	/*
1058 	 * Add the hostGroup value to the transaction entry
1059 	 */
1060 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1061 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1062 		    viewEntryPgName, STMF_VE_HOSTGROUP,
1063 		    scf_strerror(scf_error()));
1064 		ret = STMF_PS_ERROR;
1065 		goto out;
1066 	}
1067 
1068 	i++;
1069 
1070 	/*
1071 	 * Create the allTargets property
1072 	 */
1073 	if (scf_transaction_property_new(tran, entry[i],
1074 	    STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) {
1075 		if (scf_error() == SCF_ERROR_EXISTS) {
1076 			ret = STMF_PS_ERROR_EXISTS;
1077 		} else {
1078 			syslog(LOG_ERR, "transaction property new %s/%s "
1079 			    "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS,
1080 			    scf_strerror(scf_error()));
1081 			ret = STMF_PS_ERROR;
1082 		}
1083 		goto out;
1084 	}
1085 
1086 	/*
1087 	 * Set the allTargets value
1088 	 */
1089 	scfBool = viewEntry->allTargets;
1090 	scf_value_set_boolean(value[i], scfBool);
1091 
1092 	/*
1093 	 * Add the allTargets value to the transaction
1094 	 */
1095 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1096 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1097 		    viewEntryPgName, STMF_VE_ALLTARGETS,
1098 		    scf_strerror(scf_error()));
1099 		ret = STMF_PS_ERROR;
1100 		goto out;
1101 	}
1102 
1103 	i++;
1104 
1105 	/*
1106 	 * Create targetGroup property
1107 	 */
1108 	if (scf_transaction_property_new(tran, entry[i],
1109 	    STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) {
1110 		if (scf_error() == SCF_ERROR_EXISTS) {
1111 			ret = STMF_PS_ERROR_EXISTS;
1112 		} else {
1113 			syslog(LOG_ERR, "transaction property new %s/%s "
1114 			    "failed - %s", viewEntryPgName,
1115 			    STMF_VE_TARGETGROUP, scf_strerror(scf_error()));
1116 			ret = STMF_PS_ERROR;
1117 		}
1118 		goto out;
1119 	}
1120 
1121 	/*
1122 	 * Set the value for targetGroup
1123 	 */
1124 	if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) {
1125 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1126 		    viewEntryPgName, STMF_VE_TARGETGROUP,
1127 		    scf_strerror(scf_error()));
1128 		ret = STMF_PS_ERROR;
1129 		goto out;
1130 	}
1131 
1132 	/*
1133 	 * Add targetGroup value to the transaction
1134 	 */
1135 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1136 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1137 		    viewEntryPgName, STMF_VE_TARGETGROUP,
1138 		    scf_strerror(scf_error()));
1139 		ret = STMF_PS_ERROR;
1140 		goto out;
1141 	}
1142 
1143 	i++;
1144 
1145 	/*
1146 	 * Create the luNbr property
1147 	 */
1148 	if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR,
1149 	    SCF_TYPE_OPAQUE) == -1) {
1150 		if (scf_error() == SCF_ERROR_EXISTS) {
1151 			ret = STMF_PS_ERROR_EXISTS;
1152 		} else {
1153 			syslog(LOG_ERR, "transaction property new %s/%s "
1154 			    "failed - %s", viewEntryPgName, STMF_VE_LUNBR,
1155 			    scf_strerror(scf_error()));
1156 			ret = STMF_PS_ERROR;
1157 		}
1158 		goto out;
1159 	}
1160 
1161 	/*
1162 	 * Set the luNbr
1163 	 */
1164 	if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr,
1165 	    sizeof (viewEntry->luNbr)) == -1) {
1166 		syslog(LOG_ERR, "set value %s/%s failed - %s",
1167 		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
1168 		ret = STMF_PS_ERROR;
1169 		goto out;
1170 	}
1171 
1172 	/*
1173 	 * Add luNbr to the transaction entry
1174 	 */
1175 	if (scf_entry_add_value(entry[i], value[i]) == -1) {
1176 		syslog(LOG_ERR, "add value %s/%s failed - %s",
1177 		    viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
1178 		ret = STMF_PS_ERROR;
1179 		goto out;
1180 	}
1181 
1182 	/*
1183 	 * Now that we've successfully added the view entry,
1184 	 * update the logical unit property group or create
1185 	 * it if it does not exist
1186 	 */
1187 	ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD);
1188 
1189 	/*
1190 	 * If we did not add the view entry name to the logical unit,
1191 	 * make sure we do not commit the transaction
1192 	 */
1193 	if (ret != STMF_PS_SUCCESS) {
1194 		goto out;
1195 	}
1196 
1197 	/*
1198 	 * Commit property transaction
1199 	 */
1200 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
1201 		syslog(LOG_ERR, "transaction commit for add %s failed - %s",
1202 		    viewEntryPgName, scf_strerror(scf_error()));
1203 		if (commitRet == 0) {
1204 			ret = STMF_PS_ERROR_BUSY;
1205 		} else {
1206 			ret = STMF_PS_ERROR;
1207 		}
1208 	}
1209 
1210 	if (ret != STMF_PS_SUCCESS) {
1211 		/*
1212 		 * If we did not commit, try to remove the view entry name
1213 		 * from the logical unit.
1214 		 * If that fails, we're now inconsistent.
1215 		 */
1216 		backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
1217 		    REMOVE);
1218 
1219 		if (backoutRet != STMF_PS_SUCCESS) {
1220 			syslog(LOG_ERR, "remove lu view entry %s failed"
1221 			    "possible inconsistency - %s", luPgName,
1222 			    scf_strerror(scf_error()));
1223 		}
1224 		/*
1225 		 * We are still in an error scenario even though the remove
1226 		 * lu view entry succeeded.
1227 		 */
1228 		goto out;
1229 	}
1230 
1231 out:
1232 	/*
1233 	 * Free resources
1234 	 */
1235 	if (handle != NULL) {
1236 		scf_handle_destroy(handle);
1237 	}
1238 	if (svc != NULL) {
1239 		scf_service_destroy(svc);
1240 	}
1241 	/* if there was an error, delete the created pg if one was created */
1242 	if ((ret != STMF_PS_SUCCESS) && createdVePg) {
1243 		if (scf_pg_delete(pg) == -1) {
1244 			syslog(LOG_ERR, "delete VE pg %s failed - %s",
1245 			    viewEntryPgName, scf_strerror(scf_error()));
1246 		}
1247 	}
1248 	if (pg != NULL) {
1249 		scf_pg_destroy(pg);
1250 	}
1251 	if (tran != NULL) {
1252 		scf_transaction_destroy(tran);
1253 	}
1254 	/*
1255 	 * Free value and entry scf resources
1256 	 */
1257 	if (i > 0) {
1258 		for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) {
1259 			if (value[j] != NULL)
1260 				scf_value_destroy(value[j]);
1261 			if (entry[j] != NULL)
1262 				scf_entry_destroy(entry[j]);
1263 		}
1264 	}
1265 
1266 	return (ret);
1267 }
1268 /*
1269  * psClearProviderData
1270  *
1271  * providerName - name of provider data to clear
1272  */
1273 int
1274 psClearProviderData(char *providerName, int providerType)
1275 {
1276 	scf_handle_t	*handle = NULL;
1277 	scf_service_t	*svc = NULL;
1278 	scf_propertygroup_t	*pg = NULL;
1279 	char pgName[MAXPATHLEN];
1280 	int ret = STMF_PS_SUCCESS;
1281 	boolean_t pgNotFound = B_FALSE;
1282 
1283 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
1284 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
1285 		ret = STMF_PS_ERROR_INVALID_ARG;
1286 		goto out;
1287 	}
1288 
1289 	ret = iPsInit(&handle, &svc);
1290 	if (ret != STMF_PS_SUCCESS) {
1291 		goto out;
1292 	}
1293 
1294 	/*
1295 	 * Allocate scf resources
1296 	 */
1297 	if ((pg = scf_pg_create(handle)) == NULL) {
1298 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1299 		    scf_strerror(scf_error()));
1300 		ret = STMF_PS_ERROR;
1301 		goto out;
1302 	}
1303 
1304 	/*
1305 	 * create the property group name
1306 	 */
1307 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
1308 	    STMF_PROVIDER_DATA_PREFIX, providerName);
1309 
1310 	/*
1311 	 * delete provider property group
1312 	 */
1313 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1314 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
1315 			syslog(LOG_ERR, "get pg %s failed - %s",
1316 			    pgName, scf_strerror(scf_error()));
1317 			ret = STMF_PS_ERROR;
1318 			goto out;
1319 		} else {
1320 			pgNotFound = B_TRUE;
1321 		}
1322 	}
1323 
1324 	if (!pgNotFound && (scf_pg_delete(pg) == -1)) {
1325 		syslog(LOG_ERR, "delete pg %s failed - %s",
1326 		    pgName, scf_strerror(scf_error()));
1327 		ret = STMF_PS_ERROR;
1328 		goto out;
1329 	}
1330 
1331 	if (pgNotFound) {
1332 		ret = STMF_PS_ERROR_NOT_FOUND;
1333 	}
1334 
1335 out:
1336 	/*
1337 	 * Free resources
1338 	 */
1339 	if (handle != NULL) {
1340 		scf_handle_destroy(handle);
1341 	}
1342 	if (svc != NULL) {
1343 		scf_service_destroy(svc);
1344 	}
1345 	if (pg != NULL) {
1346 		scf_pg_destroy(pg);
1347 	}
1348 
1349 	return (ret);
1350 }
1351 
1352 /*
1353  * iPsCreateDeleteGroup
1354  *
1355  * Creates or deletes a group (target or host)
1356  *
1357  * When creating a group, two properties are created. One to hold the group
1358  * name and the other to hold the group members.
1359  *
1360  * pgName - Property group name
1361  * groupName - group name to create
1362  * addRemoveFlag - ADD_GROUP/REMOVE_GROUP
1363  *
1364  * returns:
1365  *  STMF_PS_SUCCESS on success
1366  *  STMF_PS_ERROR_* on failure
1367  */
1368 static int
1369 iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag)
1370 {
1371 	scf_handle_t	*handle = NULL;
1372 	scf_service_t	*svc = NULL;
1373 	scf_propertygroup_t	*pg = NULL;
1374 	scf_property_t	*prop = NULL;
1375 	scf_iter_t	*propIter = NULL;
1376 	scf_transaction_t   *tran = NULL;
1377 	scf_transaction_entry_t *entry1 = NULL;
1378 	scf_transaction_entry_t *entry2 = NULL;
1379 	scf_value_t *value = NULL;
1380 	uint64_t groupIdx;
1381 	char buf1[MAXNAMELEN];
1382 	char buf2[MAXNAMELEN];
1383 	char tmpbuf[MAXNAMELEN];
1384 	boolean_t found = B_FALSE;
1385 	int ret = STMF_PS_SUCCESS;
1386 	int commitRet;
1387 
1388 	assert(groupName != NULL);
1389 
1390 	ret = iPsInit(&handle, &svc);
1391 	if (ret != STMF_PS_SUCCESS) {
1392 		goto out;
1393 	}
1394 
1395 	/*
1396 	 * Allocate scf resources
1397 	 */
1398 	if (((pg = scf_pg_create(handle)) == NULL) ||
1399 	    ((tran = scf_transaction_create(handle)) == NULL) ||
1400 	    ((entry1 = scf_entry_create(handle)) == NULL) ||
1401 	    ((entry2 = scf_entry_create(handle)) == NULL) ||
1402 	    ((prop = scf_property_create(handle)) == NULL) ||
1403 	    ((propIter = scf_iter_create(handle)) == NULL) ||
1404 	    ((value = scf_value_create(handle)) == NULL)) {
1405 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1406 		    scf_strerror(scf_error()));
1407 		ret = STMF_PS_ERROR;
1408 		goto out;
1409 	}
1410 
1411 	/*
1412 	 * Get the property group being modified
1413 	 */
1414 	if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
1415 		if (scf_error() == SCF_ERROR_NOT_FOUND &&
1416 		    addRemoveFlag == ADD) {
1417 			if (scf_service_add_pg(svc, pgRefName,
1418 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
1419 				syslog(LOG_ERR, "add pg %s failed - %s",
1420 				    pgRefName, scf_strerror(scf_error()));
1421 				ret = STMF_PS_ERROR;
1422 			}
1423 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
1424 			syslog(LOG_ERR, "get pg %s failed - %s",
1425 			    pgRefName, scf_strerror(scf_error()));
1426 			ret = STMF_PS_ERROR_NOT_FOUND;
1427 		} else {
1428 			syslog(LOG_ERR, "get pg %s failed - %s",
1429 			    pgRefName, scf_strerror(scf_error()));
1430 			ret = STMF_PS_ERROR;
1431 		}
1432 		if (ret != STMF_PS_SUCCESS) {
1433 			goto out;
1434 		}
1435 	}
1436 
1437 	/*
1438 	 * propIter is the iterator handle
1439 	 */
1440 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1441 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1442 		    pgRefName, scf_strerror(scf_error()));
1443 		ret = STMF_PS_ERROR;
1444 		goto out;
1445 	}
1446 
1447 	/*
1448 	 * Iterate through the group names.
1449 	 * If we find it in the list, it's an error when addRemoveFlag == ADD.
1450 	 */
1451 	while (scf_iter_next_property(propIter, prop) == 1) {
1452 		if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
1453 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1454 			    pgRefName, scf_strerror(scf_error()));
1455 			ret = STMF_PS_ERROR;
1456 			break;
1457 		}
1458 		/*
1459 		 * Skip over member list properties
1460 		 */
1461 		if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
1462 			continue;
1463 		}
1464 		if (scf_property_get_value(prop, value) == -1) {
1465 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
1466 			    pgRefName, buf1, scf_strerror(scf_error()));
1467 			ret = STMF_PS_ERROR;
1468 			break;
1469 		}
1470 		if (scf_value_get_ustring(value, tmpbuf,
1471 		    sizeof (tmpbuf)) == -1) {
1472 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
1473 			    pgRefName, buf1, scf_strerror(scf_error()));
1474 			ret = STMF_PS_ERROR;
1475 			break;
1476 		}
1477 
1478 		if ((strlen(tmpbuf) == strlen(groupName)) &&
1479 		    bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) {
1480 			if (addRemoveFlag == ADD) {
1481 				ret = STMF_PS_ERROR_EXISTS;
1482 			}
1483 			found = B_TRUE;
1484 			/*
1485 			 * buf1 contains the name for REMOVE
1486 			 */
1487 			break;
1488 		}
1489 	}
1490 
1491 	if (ret != STMF_PS_SUCCESS) {
1492 		goto out;
1493 	}
1494 
1495 	scf_value_reset(value);
1496 
1497 	if (!found && addRemoveFlag == REMOVE) {
1498 		ret = STMF_PS_ERROR_NOT_FOUND;
1499 		goto out;
1500 	}
1501 
1502 	/*
1503 	 * If we're adding, we need to create a new property name for the
1504 	 * new group
1505 	 */
1506 	if (addRemoveFlag == ADD) {
1507 		for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) {
1508 			if (snprintf(buf1, sizeof (buf1), "%s-%lld",
1509 			    STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) {
1510 				syslog(LOG_ERR,
1511 				    "buffer overflow on property name %s",
1512 				    buf1);
1513 				ret = STMF_PS_ERROR;
1514 				break;
1515 			}
1516 			if (scf_pg_get_property(pg, buf1, prop) == -1) {
1517 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
1518 					syslog(LOG_ERR, "get property %s/%s "
1519 					    "failed - %s", pgRefName, buf1,
1520 					    scf_strerror(scf_error()));
1521 					ret = STMF_PS_ERROR;
1522 				}
1523 				break;
1524 			}
1525 		}
1526 	}
1527 
1528 	/*
1529 	 * Now create the new member list property for the new group
1530 	 */
1531 	if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
1532 	    STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
1533 		syslog(LOG_ERR, "buffer overflow on property name %s",
1534 		    buf1);
1535 		ret = STMF_PS_ERROR;
1536 		goto out;
1537 	}
1538 
1539 	/*
1540 	 * buf1 now contains the name of the property if it was found in the
1541 	 * list in the case of delete or the next available property name
1542 	 * in the case of create
1543 	 *
1544 	 * buf2 now contains the member list property name
1545 	 */
1546 	if (scf_transaction_start(tran, pg) == -1) {
1547 		syslog(LOG_ERR, "start transaction for %s failed - %s",
1548 		    pgRefName, scf_strerror(scf_error()));
1549 		ret = STMF_PS_ERROR;
1550 		goto out;
1551 	}
1552 
1553 	if (addRemoveFlag == ADD) {
1554 		/*
1555 		 * Create the property 'group name'
1556 		 * This is the container for the group name
1557 		 */
1558 		if (scf_transaction_property_new(tran, entry1, buf1,
1559 		    SCF_TYPE_USTRING) == -1) {
1560 			syslog(LOG_ERR, "transaction property new %s/%s "
1561 			    "failed - %s", pgRefName, buf1,
1562 			    scf_strerror(scf_error()));
1563 			ret = STMF_PS_ERROR;
1564 			goto out;
1565 		}
1566 		if (scf_value_set_ustring(value, groupName) == -1) {
1567 			syslog(LOG_ERR, "set ustring %s/%s failed - %s",
1568 			    pgRefName, buf1, scf_strerror(scf_error()));
1569 			ret = STMF_PS_ERROR;
1570 			goto out;
1571 		}
1572 		if (scf_entry_add_value(entry1, value) == -1) {
1573 			syslog(LOG_ERR, "add value %s/%s failed - %s",
1574 			    pgRefName, buf1, scf_strerror(scf_error()));
1575 			ret = STMF_PS_ERROR;
1576 			goto out;
1577 		}
1578 		/*
1579 		 * Create the property 'group list'
1580 		 * This is the container for the group members
1581 		 */
1582 		if (scf_transaction_property_new(tran, entry2, buf2,
1583 		    SCF_TYPE_USTRING) == -1) {
1584 			syslog(LOG_ERR, "transaction property new %s/%s "
1585 			    "failed - %s", pgRefName, buf2,
1586 			    scf_strerror(scf_error()));
1587 			ret = STMF_PS_ERROR;
1588 			goto out;
1589 		}
1590 	} else {
1591 		/*
1592 		 * Delete the property 'group name'
1593 		 */
1594 		if (scf_transaction_property_delete(tran, entry1, buf1)
1595 		    == -1) {
1596 			syslog(LOG_ERR,
1597 			    "transaction property delete %s/%s failed - %s",
1598 			    pgRefName, buf1, scf_strerror(scf_error()));
1599 			ret = STMF_PS_ERROR;
1600 			goto out;
1601 		}
1602 		/*
1603 		 * Delete the property 'group list'
1604 		 */
1605 		if (scf_transaction_property_delete(tran, entry2, buf2)
1606 		    == -1) {
1607 			syslog(LOG_ERR, "transaction property delete %s/%s "
1608 			    "failed - %s", pgRefName, buf2,
1609 			    scf_strerror(scf_error()));
1610 			ret = STMF_PS_ERROR;
1611 			goto out;
1612 		}
1613 	}
1614 
1615 	if (ret != STMF_PS_SUCCESS) {
1616 		goto out;
1617 	}
1618 
1619 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
1620 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
1621 		    pgRefName, scf_strerror(scf_error()));
1622 		if (commitRet == 0) {
1623 			ret = STMF_PS_ERROR_BUSY;
1624 		} else {
1625 			ret = STMF_PS_ERROR;
1626 		}
1627 	}
1628 
1629 out:
1630 	/*
1631 	 * Free resources
1632 	 */
1633 	if (handle != NULL) {
1634 		scf_handle_destroy(handle);
1635 	}
1636 	if (svc != NULL) {
1637 		scf_service_destroy(svc);
1638 	}
1639 	if (pg != NULL) {
1640 		scf_pg_destroy(pg);
1641 	}
1642 	if (tran != NULL) {
1643 		scf_transaction_destroy(tran);
1644 	}
1645 	if (entry1 != NULL) {
1646 		scf_entry_destroy(entry1);
1647 	}
1648 	if (entry2 != NULL) {
1649 		scf_entry_destroy(entry2);
1650 	}
1651 	if (prop != NULL) {
1652 		scf_property_destroy(prop);
1653 	}
1654 	if (propIter != NULL) {
1655 		scf_iter_destroy(propIter);
1656 	}
1657 	if (value != NULL) {
1658 		scf_value_destroy(value);
1659 	}
1660 
1661 	return (ret);
1662 }
1663 
1664 /*
1665  * iPsGetGroupList
1666  *
1667  * pgName - Property group name
1668  * groupList - pointer to pointer to stmfGroupList structure. On success,
1669  * contains the list of groups
1670  *
1671  * returns:
1672  *  STMF_PS_SUCCESS on success
1673  *  STMF_PS_ERROR_* on failure
1674  */
1675 static int
1676 iPsGetGroupList(char *pgName, stmfGroupList **groupList)
1677 {
1678 	scf_handle_t	*handle = NULL;
1679 	scf_service_t	*svc = NULL;
1680 	scf_propertygroup_t	*pg = NULL;
1681 	scf_property_t	*prop = NULL;
1682 	scf_iter_t	*propIter = NULL;
1683 	scf_value_t	*value = NULL;
1684 	char buf[MAXNAMELEN];
1685 	int memberCnt = 0;
1686 	int i = 0;
1687 	int ret = STMF_PS_SUCCESS;
1688 
1689 	assert(groupList != NULL);
1690 
1691 	ret = iPsInit(&handle, &svc);
1692 	if (ret != STMF_PS_SUCCESS) {
1693 		goto out;
1694 	}
1695 
1696 	/*
1697 	 * Allocate scf resources
1698 	 */
1699 	if (((pg = scf_pg_create(handle)) == NULL) ||
1700 	    ((prop = scf_property_create(handle)) == NULL) ||
1701 	    ((propIter = scf_iter_create(handle)) == NULL) ||
1702 	    ((value = scf_value_create(handle)) == NULL)) {
1703 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1704 		    scf_strerror(scf_error()));
1705 		ret = STMF_PS_ERROR;
1706 		goto out;
1707 	}
1708 
1709 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1710 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1711 			syslog(LOG_ERR, "get pg %s failed - %s",
1712 			    pgName, scf_strerror(scf_error()));
1713 			ret = STMF_PS_ERROR_NOT_FOUND;
1714 		} else {
1715 			syslog(LOG_ERR, "get pg %s failed - %s",
1716 			    pgName, scf_strerror(scf_error()));
1717 			ret = STMF_PS_ERROR;
1718 		}
1719 		goto out;
1720 	}
1721 
1722 	/*
1723 	 * propIter is the iterator handle
1724 	 */
1725 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1726 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1727 		    pgName, scf_strerror(scf_error()));
1728 		ret = STMF_PS_ERROR;
1729 		goto out;
1730 	}
1731 
1732 	while (scf_iter_next_property(propIter, prop) == 1) {
1733 		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
1734 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1735 			    pgName, scf_strerror(scf_error()));
1736 			ret = STMF_PS_ERROR;
1737 			break;
1738 		}
1739 		/*
1740 		 * Skip over member list properties
1741 		 */
1742 		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
1743 			continue;
1744 		}
1745 		memberCnt++;
1746 	}
1747 
1748 	/*
1749 	 * propIter is the iterator handle
1750 	 */
1751 	if (scf_iter_pg_properties(propIter, pg) == -1) {
1752 		syslog(LOG_ERR, "iter properties for %s failed - %s",
1753 		    pgName, scf_strerror(scf_error()));
1754 		ret = STMF_PS_ERROR;
1755 		goto out;
1756 	}
1757 
1758 	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
1759 	    memberCnt * sizeof (stmfGroupName));
1760 
1761 	if (*groupList == NULL) {
1762 		ret = STMF_PS_ERROR_NOMEM;
1763 		goto out;
1764 	}
1765 
1766 	/*
1767 	 * In order to get a list of groups, simply get all of the
1768 	 * properties that are not member list properties, i.e. the group
1769 	 * name properties.
1770 	 * It's possible for this list to grow beyond what was originally
1771 	 * read so just ensure we're not writing beyond our allocated buffer
1772 	 * by ensuring i < memberCnt
1773 	 */
1774 	while ((scf_iter_next_property(propIter, prop) == 1) &&
1775 	    (i < memberCnt)) {
1776 		if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
1777 			syslog(LOG_ERR, "get name from %s iter failed - %s",
1778 			    pgName, scf_strerror(scf_error()));
1779 			ret = STMF_PS_ERROR;
1780 			break;
1781 		}
1782 		/*
1783 		 * Skip over member list properties
1784 		 */
1785 		if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
1786 			continue;
1787 		}
1788 		if (scf_property_get_value(prop, value) == -1) {
1789 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
1790 			    pgName, buf, scf_strerror(scf_error()));
1791 			ret = STMF_PS_ERROR;
1792 			break;
1793 		}
1794 		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
1795 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
1796 			    pgName, buf, scf_strerror(scf_error()));
1797 			ret = STMF_PS_ERROR;
1798 			break;
1799 		}
1800 		bcopy(buf, (*groupList)->name[i++], strlen(buf));
1801 		(*groupList)->cnt++;
1802 	}
1803 
1804 	if (ret != STMF_PS_SUCCESS) {
1805 		free(*groupList);
1806 		goto out;
1807 	}
1808 
1809 out:
1810 	/*
1811 	 * Free resources
1812 	 */
1813 	if (handle != NULL) {
1814 		scf_handle_destroy(handle);
1815 	}
1816 	if (svc != NULL) {
1817 		scf_service_destroy(svc);
1818 	}
1819 	if (pg != NULL) {
1820 		scf_pg_destroy(pg);
1821 	}
1822 	if (propIter != NULL) {
1823 		scf_iter_destroy(propIter);
1824 	}
1825 	if (prop != NULL) {
1826 		scf_property_destroy(prop);
1827 	}
1828 	if (value != NULL) {
1829 		scf_value_destroy(value);
1830 	}
1831 
1832 	return (ret);
1833 }
1834 
1835 /*
1836  * iPsGetGroupMemberList
1837  *
1838  * pgName - Property group name
1839  * groupName - group name (host group or target group)
1840  * groupMemberList - pointer to pointer to stmfGroupProperties structure. On
1841  * success, contains the list of group members
1842  *
1843  * returns:
1844  *  STMF_PS_SUCCESS on success
1845  *  STMF_PS_ERROR_* on failure
1846  */
1847 static int
1848 iPsGetGroupMemberList(char *pgName, char *groupName,
1849     stmfGroupProperties **groupMemberList)
1850 {
1851 	scf_handle_t	*handle = NULL;
1852 	scf_service_t	*svc = NULL;
1853 	scf_propertygroup_t	*pg = NULL;
1854 	scf_property_t	*prop = NULL;
1855 	scf_value_t	*valueLookup = NULL;
1856 	scf_iter_t	*valueIter = NULL;
1857 	int i = 0;
1858 	int memberCnt;
1859 	int len;
1860 	int ret = STMF_PS_SUCCESS;
1861 	char buf[MAXNAMELEN];
1862 
1863 	assert(pgName != NULL && groupName != NULL);
1864 
1865 	/*
1866 	 * init the service handle
1867 	 */
1868 	ret = iPsInit(&handle, &svc);
1869 	if (ret != STMF_PS_SUCCESS) {
1870 		goto out;
1871 	}
1872 
1873 	/*
1874 	 * Allocate scf resources
1875 	 */
1876 	if (((pg = scf_pg_create(handle)) == NULL) ||
1877 	    ((prop = scf_property_create(handle)) == NULL) ||
1878 	    ((valueIter = scf_iter_create(handle)) == NULL) ||
1879 	    ((valueLookup = scf_value_create(handle)) == NULL)) {
1880 		syslog(LOG_ERR, "scf alloc resource failed - %s",
1881 		    scf_strerror(scf_error()));
1882 		ret = STMF_PS_ERROR;
1883 		goto out;
1884 	}
1885 
1886 	/*
1887 	 * get the service property group handle
1888 	 */
1889 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
1890 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
1891 			ret = STMF_PS_ERROR_NOT_FOUND;
1892 		} else {
1893 			ret = STMF_PS_ERROR;
1894 		}
1895 		syslog(LOG_ERR, "get pg %s failed - %s",
1896 		    pgName, scf_strerror(scf_error()));
1897 		goto out;
1898 	}
1899 
1900 	/*
1901 	 * Get the property handle
1902 	 * based on the target or host group name
1903 	 */
1904 	if (scf_pg_get_property(pg, groupName, prop) == -1) {
1905 		syslog(LOG_ERR, "get property %s/%s failed - %s",
1906 		    pgName, groupName, scf_strerror(scf_error()));
1907 		ret = STMF_PS_ERROR;
1908 		goto out;
1909 	}
1910 
1911 	/*
1912 	 * valueIter is the iterator handle
1913 	 */
1914 	if (scf_iter_property_values(valueIter, prop) == -1) {
1915 		syslog(LOG_ERR, "iter value %s/%s failed - %s",
1916 		    pgName, groupName, scf_strerror(scf_error()));
1917 		ret = STMF_PS_ERROR;
1918 		goto out;
1919 	}
1920 
1921 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
1922 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
1923 			syslog(LOG_ERR, "iter value %s/%s failed - %s",
1924 			    pgName, groupName, scf_strerror(scf_error()));
1925 			ret = STMF_PS_ERROR;
1926 			break;
1927 		}
1928 		i++;
1929 	}
1930 
1931 	/*
1932 	 * valueIter is the iterator handle
1933 	 */
1934 	if (scf_iter_property_values(valueIter, prop) == -1) {
1935 		syslog(LOG_ERR, "iter value %s/%s failed - %s",
1936 		    pgName, groupName, scf_strerror(scf_error()));
1937 		ret = STMF_PS_ERROR;
1938 		goto out;
1939 	}
1940 
1941 	memberCnt = i;
1942 
1943 	*groupMemberList = (stmfGroupProperties *)calloc(1,
1944 	    sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid));
1945 	if (*groupMemberList == NULL) {
1946 		ret = STMF_PS_ERROR_NOMEM;
1947 		goto out;
1948 	}
1949 
1950 	i = 0;
1951 	while ((scf_iter_next_value(valueIter, valueLookup) == 1) &&
1952 	    (i < memberCnt)) {
1953 		if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN))
1954 		    == -1) {
1955 			syslog(LOG_ERR, "iter value %s/%s failed - %s",
1956 			    pgName, groupName, scf_strerror(scf_error()));
1957 			ret = STMF_PS_ERROR;
1958 			break;
1959 		}
1960 		if (len < sizeof (stmfDevid) - 1) {
1961 			(*groupMemberList)->name[i].identLength = len;
1962 			bcopy(buf,
1963 			    (*groupMemberList)->name[i++].ident, len);
1964 			(*groupMemberList)->cnt++;
1965 		} else {
1966 			ret = STMF_PS_ERROR;
1967 			break;
1968 		}
1969 	}
1970 
1971 	if (ret != STMF_PS_SUCCESS) {
1972 		free(*groupMemberList);
1973 		goto out;
1974 	}
1975 
1976 out:
1977 	/*
1978 	 * Free resources
1979 	 */
1980 	if (handle != NULL) {
1981 		scf_handle_destroy(handle);
1982 	}
1983 	if (svc != NULL) {
1984 		scf_service_destroy(svc);
1985 	}
1986 	if (pg != NULL) {
1987 		scf_pg_destroy(pg);
1988 	}
1989 	if (prop != NULL) {
1990 		scf_property_destroy(prop);
1991 	}
1992 	if (valueLookup != NULL) {
1993 		scf_value_destroy(valueLookup);
1994 	}
1995 	if (valueIter != NULL) {
1996 		scf_iter_destroy(valueIter);
1997 	}
1998 
1999 	return (ret);
2000 }
2001 
2002 int
2003 psGetServicePersist(uint8_t *persistType)
2004 {
2005 	scf_handle_t	*handle = NULL;
2006 	scf_service_t	*svc = NULL;
2007 	int ret;
2008 
2009 
2010 	ret = iPsInit(&handle, &svc);
2011 	if (ret != STMF_PS_SUCCESS) {
2012 		return (STMF_PS_ERROR);
2013 	}
2014 
2015 	ret = iPsGetSetPersistType(persistType, handle, svc, GET);
2016 
2017 	/*
2018 	 * Free resources
2019 	 */
2020 	if (handle != NULL) {
2021 		scf_handle_destroy(handle);
2022 	}
2023 	if (svc != NULL) {
2024 		scf_service_destroy(svc);
2025 	}
2026 	return (ret);
2027 }
2028 
2029 int
2030 psSetServicePersist(uint8_t persistType)
2031 {
2032 	scf_handle_t	*handle = NULL;
2033 	scf_service_t	*svc = NULL;
2034 	int ret;
2035 
2036 
2037 	ret = iPsInit(&handle, &svc);
2038 	if (ret != STMF_PS_SUCCESS) {
2039 		return (STMF_PS_ERROR);
2040 	}
2041 
2042 	ret = iPsGetSetPersistType(&persistType, handle, svc, SET);
2043 
2044 	/*
2045 	 * Free resources
2046 	 */
2047 	if (handle != NULL) {
2048 		scf_handle_destroy(handle);
2049 	}
2050 	if (svc != NULL) {
2051 		scf_service_destroy(svc);
2052 	}
2053 	return (ret);
2054 }
2055 
2056 static int
2057 iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
2058 scf_service_t *svc, int getSet)
2059 {
2060 	scf_propertygroup_t	*pg = NULL;
2061 	scf_property_t	*prop = NULL;
2062 	scf_value_t	*value = NULL;
2063 	scf_transaction_t *tran = NULL;
2064 	scf_transaction_entry_t *entry = NULL;
2065 	char iPersistTypeGet[MAXNAMELEN] = {0};
2066 	char *iPersistType;
2067 	int ret = STMF_PS_SUCCESS;
2068 	int commitRet;
2069 
2070 	if (((pg = scf_pg_create(handle)) == NULL) ||
2071 	    ((prop = scf_property_create(handle)) == NULL) ||
2072 	    ((entry = scf_entry_create(handle)) == NULL) ||
2073 	    ((tran = scf_transaction_create(handle)) == NULL) ||
2074 	    ((value = scf_value_create(handle)) == NULL)) {
2075 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2076 		    scf_strerror(scf_error()));
2077 		ret = STMF_PS_ERROR;
2078 		goto out;
2079 	}
2080 
2081 	if (getSet == GET) {
2082 		/* set to default */
2083 		*persistType = STMF_PERSIST_SMF;
2084 		iPersistType = STMF_PS_PERSIST_SMF;
2085 	}
2086 
2087 	if (getSet == SET) {
2088 		if (*persistType == STMF_PERSIST_SMF) {
2089 			iPersistType = STMF_PS_PERSIST_SMF;
2090 		} else if (*persistType == STMF_PERSIST_NONE) {
2091 			iPersistType = STMF_PS_PERSIST_NONE;
2092 		} else {
2093 			ret = STMF_PS_ERROR;
2094 			goto out;
2095 		}
2096 	}
2097 
2098 	/*
2099 	 * get stmf data property group
2100 	 */
2101 	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
2102 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2103 			ret = STMF_PS_ERROR_NOT_FOUND;
2104 		} else {
2105 			ret = STMF_PS_ERROR;
2106 		}
2107 		syslog(LOG_ERR, "get pg %s failed - %s",
2108 		    STMF_DATA_GROUP, scf_strerror(scf_error()));
2109 
2110 		goto out;
2111 	}
2112 
2113 	/* find persistence property */
2114 	/*
2115 	 * Get the persistence property
2116 	 */
2117 	if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
2118 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2119 			ret = STMF_PS_ERROR_NOT_FOUND;
2120 		} else {
2121 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2122 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2123 			    scf_strerror(scf_error()));
2124 			ret = STMF_PS_ERROR;
2125 			goto out;
2126 		}
2127 	}
2128 
2129 	/* no persist property found */
2130 	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
2131 		/*
2132 		 * If we have no persistType property, go ahead
2133 		 * and create it with the user specified value or
2134 		 * the default value.
2135 		 */
2136 		/*
2137 		 * Begin the transaction
2138 		 */
2139 		if (scf_transaction_start(tran, pg) == -1) {
2140 			syslog(LOG_ERR, "start transaction for %s failed - %s",
2141 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2142 			ret = STMF_PS_ERROR;
2143 			goto out;
2144 		}
2145 
2146 		/* is this a SET or GET w/error? */
2147 		if (ret) {
2148 			if (scf_transaction_property_new(tran, entry,
2149 			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
2150 				syslog(LOG_ERR, "transaction property new "
2151 				    "%s/%s failed - %s", STMF_DATA_GROUP,
2152 				    STMF_PERSIST_TYPE,
2153 				    scf_strerror(scf_error()));
2154 				ret = STMF_PS_ERROR;
2155 				goto out;
2156 			}
2157 		} else {
2158 			if (scf_transaction_property_change(tran, entry,
2159 			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
2160 				syslog(LOG_ERR, "transaction property change "
2161 				    "%s/%s failed - %s", STMF_DATA_GROUP,
2162 				    STMF_PERSIST_TYPE,
2163 				    scf_strerror(scf_error()));
2164 				ret = STMF_PS_ERROR;
2165 				goto out;
2166 			}
2167 		}
2168 
2169 		/*
2170 		 * set the persist type
2171 		 */
2172 		if (scf_value_set_astring(value, iPersistType) == -1) {
2173 			syslog(LOG_ERR, "set value %s/%s failed - %s",
2174 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2175 			    scf_strerror(scf_error()));
2176 			ret = STMF_PS_ERROR;
2177 			goto out;
2178 		}
2179 
2180 		/*
2181 		 * add the value to the transaction
2182 		 */
2183 		if (scf_entry_add_value(entry, value) == -1) {
2184 			syslog(LOG_ERR, "add value %s/%s failed - %s",
2185 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2186 			    scf_strerror(scf_error()));
2187 			ret = STMF_PS_ERROR;
2188 			goto out;
2189 		}
2190 		if ((commitRet = scf_transaction_commit(tran)) != 1) {
2191 			syslog(LOG_ERR, "transaction commit for %s failed - %s",
2192 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2193 			if (commitRet == 0) {
2194 				ret = STMF_PS_ERROR_BUSY;
2195 			} else {
2196 				ret = STMF_PS_ERROR;
2197 			}
2198 			goto out;
2199 		}
2200 		/* reset return value */
2201 		ret = STMF_PS_SUCCESS;
2202 	} else if (getSet == GET) {
2203 		/* get the persist property */
2204 		if (scf_property_get_value(prop, value) == -1) {
2205 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2206 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2207 			    scf_strerror(scf_error()));
2208 			ret = STMF_PS_ERROR;
2209 			goto out;
2210 		}
2211 
2212 		/*
2213 		 * Get the value of the persist property
2214 		 */
2215 		if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
2216 		    == -1) {
2217 			syslog(LOG_ERR, "get string value %s/%s failed - %s",
2218 			    STMF_DATA_GROUP, STMF_PERSIST_TYPE,
2219 			    scf_strerror(scf_error()));
2220 			ret = STMF_PS_ERROR;
2221 			goto out;
2222 		}
2223 	}
2224 
2225 	if (getSet == GET) {
2226 		if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
2227 			*persistType = STMF_PERSIST_NONE;
2228 		} else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
2229 			*persistType = STMF_PERSIST_SMF;
2230 		} else {
2231 			ret = STMF_PS_ERROR;
2232 			goto out;
2233 		}
2234 	}
2235 out:
2236 	/*
2237 	 * Free resources.
2238 	 * handle and svc should not be free'd here. They're
2239 	 * free'd elsewhere
2240 	 */
2241 	if (pg != NULL) {
2242 		scf_pg_destroy(pg);
2243 	}
2244 	if (prop != NULL) {
2245 		scf_property_destroy(prop);
2246 	}
2247 	if (entry != NULL) {
2248 		scf_entry_destroy(entry);
2249 	}
2250 	if (tran != NULL) {
2251 		scf_transaction_destroy(tran);
2252 	}
2253 	if (value != NULL) {
2254 		scf_value_destroy(value);
2255 	}
2256 	return (ret);
2257 }
2258 
2259 /*
2260  * Initialize scf stmf service access
2261  * handle - returned handle
2262  * service - returned service handle
2263  *
2264  * Both handle and service must be destroyed by the caller
2265  */
2266 static int
2267 iPsInit(scf_handle_t **handle, scf_service_t **service)
2268 {
2269 	scf_scope_t	*scope = NULL;
2270 	uint64_t version;
2271 	int ret;
2272 
2273 	assert(handle != NULL && service != NULL);
2274 
2275 	if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
2276 		syslog(LOG_ERR, "scf_handle_create failed - %s",
2277 		    scf_strerror(scf_error()));
2278 		ret = STMF_PS_ERROR;
2279 		goto err;
2280 	}
2281 
2282 	if (scf_handle_bind(*handle) == -1) {
2283 		syslog(LOG_ERR, "scf_handle_bind failed - %s",
2284 		    scf_strerror(scf_error()));
2285 		ret = STMF_PS_ERROR;
2286 		goto err;
2287 	}
2288 
2289 	if ((*service = scf_service_create(*handle)) == NULL) {
2290 		syslog(LOG_ERR, "scf_service_create failed - %s",
2291 		    scf_strerror(scf_error()));
2292 		ret = STMF_PS_ERROR;
2293 		goto err;
2294 	}
2295 
2296 	if ((scope = scf_scope_create(*handle)) == NULL) {
2297 		syslog(LOG_ERR, "scf_scope_create failed - %s",
2298 		    scf_strerror(scf_error()));
2299 		ret = STMF_PS_ERROR;
2300 		goto err;
2301 	}
2302 
2303 	if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
2304 		syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
2305 		    scf_strerror(scf_error()));
2306 		ret = STMF_PS_ERROR;
2307 		goto err;
2308 	}
2309 
2310 	if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) {
2311 		syslog(LOG_ERR, "scf_scope_get_service failed - %s",
2312 		    scf_strerror(scf_error()));
2313 		ret = STMF_PS_ERROR_SERVICE_NOT_FOUND;
2314 		goto err;
2315 	}
2316 
2317 
2318 	/*
2319 	 * Get and check the version number
2320 	 */
2321 	ret = iPsGetServiceVersion(&version, *handle, *service);
2322 	if (ret != STMF_PS_SUCCESS) {
2323 		goto err;
2324 	}
2325 
2326 	if (version != STMF_SMF_VERSION) {
2327 		ret = STMF_PS_ERROR_VERSION_MISMATCH;
2328 		goto err;
2329 	}
2330 
2331 	/* we only need destroy the scope here */
2332 	scf_scope_destroy(scope);
2333 
2334 	return (STMF_PS_SUCCESS);
2335 
2336 err:
2337 	if (*handle != NULL) {
2338 		scf_handle_destroy(*handle);
2339 	}
2340 	if (*service != NULL) {
2341 		scf_service_destroy(*service);
2342 		*service = NULL;
2343 	}
2344 	if (scope != NULL) {
2345 		scf_scope_destroy(scope);
2346 	}
2347 	return (ret);
2348 }
2349 
2350 
2351 /*
2352  * called by iPsInit only
2353  * iPsGetServiceVersion
2354  */
2355 static int
2356 iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle,
2357 scf_service_t *svc)
2358 {
2359 	scf_propertygroup_t	*pg = NULL;
2360 	scf_property_t	*prop = NULL;
2361 	scf_value_t	*value = NULL;
2362 	scf_transaction_t *tran = NULL;
2363 	scf_transaction_entry_t *entry = NULL;
2364 	int ret = STMF_PS_SUCCESS;
2365 	int commitRet;
2366 
2367 	if (((pg = scf_pg_create(handle)) == NULL) ||
2368 	    ((prop = scf_property_create(handle)) == NULL) ||
2369 	    ((entry = scf_entry_create(handle)) == NULL) ||
2370 	    ((tran = scf_transaction_create(handle)) == NULL) ||
2371 	    ((value = scf_value_create(handle)) == NULL)) {
2372 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2373 		    scf_strerror(scf_error()));
2374 		ret = STMF_PS_ERROR;
2375 		goto out;
2376 	}
2377 
2378 	*version = STMF_SMF_VERSION;
2379 
2380 	/*
2381 	 * get stmf data property group
2382 	 */
2383 	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
2384 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2385 			ret = STMF_PS_ERROR_NOT_FOUND;
2386 		} else {
2387 			syslog(LOG_ERR, "get pg %s failed - %s",
2388 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2389 			ret = STMF_PS_ERROR;
2390 			goto out;
2391 		}
2392 	}
2393 
2394 	/* create the group */
2395 	if (ret == STMF_PS_ERROR_NOT_FOUND) {
2396 		/*
2397 		 * create the property group.
2398 		 */
2399 		if (scf_service_add_pg(svc, STMF_DATA_GROUP,
2400 		    SCF_GROUP_APPLICATION, 0, pg) == -1) {
2401 			syslog(LOG_ERR, "add pg %s failed - %s",
2402 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2403 			ret = STMF_PS_ERROR;
2404 			goto out;
2405 		}
2406 		/* reset return value */
2407 		ret = STMF_PS_SUCCESS;
2408 	}
2409 
2410 	/* find version property */
2411 	/*
2412 	 * Get the version property
2413 	 */
2414 	if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
2415 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2416 			ret = STMF_PS_ERROR_NOT_FOUND;
2417 		} else {
2418 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2419 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2420 			    scf_strerror(scf_error()));
2421 			ret = STMF_PS_ERROR;
2422 			goto out;
2423 		}
2424 	}
2425 
2426 	/* no version property found */
2427 	if (ret == STMF_PS_ERROR_NOT_FOUND) {
2428 		/*
2429 		 * If we have no version property, go ahead
2430 		 * and create it. We're obviously making an assumption
2431 		 * here that someone did not delete the existing property
2432 		 * and that this is the initial set and the initial call
2433 		 * to iPsInit.
2434 		 * If they did delete it, this will simply plant this
2435 		 * library's version on this service. That may or may not be
2436 		 * correct and we have no way of determining that.
2437 		 */
2438 		/*
2439 		 * Begin the transaction
2440 		 */
2441 		if (scf_transaction_start(tran, pg) == -1) {
2442 			syslog(LOG_ERR, "start transaction for %s failed - %s",
2443 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2444 			ret = STMF_PS_ERROR;
2445 			goto out;
2446 		}
2447 
2448 		if (scf_transaction_property_new(tran, entry,
2449 		    STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) {
2450 			syslog(LOG_ERR,
2451 			    "transaction property new %s/%s failed - %s",
2452 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2453 			    scf_strerror(scf_error()));
2454 			ret = STMF_PS_ERROR;
2455 			goto out;
2456 		}
2457 
2458 		/*
2459 		 * set the version number
2460 		 */
2461 		scf_value_set_count(value, *version);
2462 
2463 		/*
2464 		 * add the value to the transaction
2465 		 */
2466 		if (scf_entry_add_value(entry, value) == -1) {
2467 			syslog(LOG_ERR, "add value %s/%s failed - %s",
2468 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2469 			    scf_strerror(scf_error()));
2470 			ret = STMF_PS_ERROR;
2471 			goto out;
2472 		}
2473 		if ((commitRet = scf_transaction_commit(tran)) != 1) {
2474 			syslog(LOG_ERR, "transaction commit for %s failed - %s",
2475 			    STMF_DATA_GROUP, scf_strerror(scf_error()));
2476 			if (commitRet == 0) {
2477 				ret = STMF_PS_ERROR_BUSY;
2478 			} else {
2479 				ret = STMF_PS_ERROR;
2480 			}
2481 			goto out;
2482 		}
2483 		/* reset return value */
2484 		ret = STMF_PS_SUCCESS;
2485 	} else {
2486 		/* get the version property */
2487 		if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
2488 			syslog(LOG_ERR, "get property %s/%s failed - %s",
2489 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2490 			    scf_strerror(scf_error()));
2491 			ret = STMF_PS_ERROR;
2492 			goto out;
2493 		}
2494 
2495 		if (scf_property_get_value(prop, value) == -1) {
2496 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2497 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2498 			    scf_strerror(scf_error()));
2499 			ret = STMF_PS_ERROR;
2500 			goto out;
2501 		}
2502 
2503 		/*
2504 		 * Get the actual value of the view entry count property
2505 		 */
2506 		if (scf_value_get_count(value, version) == -1) {
2507 			syslog(LOG_ERR, "get count value %s/%s failed - %s",
2508 			    STMF_DATA_GROUP, STMF_VERSION_NAME,
2509 			    scf_strerror(scf_error()));
2510 			ret = STMF_PS_ERROR;
2511 			goto out;
2512 		}
2513 	}
2514 
2515 out:
2516 	/*
2517 	 * Free resources.
2518 	 * handle and svc should not be free'd here. They're
2519 	 * free'd elsewhere
2520 	 */
2521 	if (pg != NULL) {
2522 		scf_pg_destroy(pg);
2523 	}
2524 	if (prop != NULL) {
2525 		scf_property_destroy(prop);
2526 	}
2527 	if (entry != NULL) {
2528 		scf_entry_destroy(entry);
2529 	}
2530 	if (tran != NULL) {
2531 		scf_transaction_destroy(tran);
2532 	}
2533 	if (value != NULL) {
2534 		scf_value_destroy(value);
2535 	}
2536 	return (ret);
2537 }
2538 
2539 
2540 
2541 /*
2542  * iPsGetActualGroupName
2543  *
2544  * pgName - Property group name
2545  * groupName - requested group name
2546  * actualName - actual group name to reference (len must be >= MAXNAMELEN)
2547  *
2548  * returns:
2549  *  STMF_PS_SUCCESS on success
2550  *  STMF_PS_ERROR_* on failure
2551  */
2552 static int
2553 iPsGetActualGroupName(char *pgName, char *groupName, char *actualName)
2554 {
2555 	scf_handle_t	*handle = NULL;
2556 	scf_service_t	*svc = NULL;
2557 	scf_propertygroup_t	*pg = NULL;
2558 	scf_property_t	*prop = NULL;
2559 	scf_iter_t	*propIter = NULL;
2560 	scf_value_t	*value = NULL;
2561 	char buf[MAXNAMELEN];
2562 	int ret;
2563 
2564 	ret = iPsInit(&handle, &svc);
2565 	if (ret != STMF_PS_SUCCESS) {
2566 		goto out;
2567 	}
2568 
2569 	/*
2570 	 * Allocate scf resources
2571 	 */
2572 	if (((pg = scf_pg_create(handle)) == NULL) ||
2573 	    ((prop = scf_property_create(handle)) == NULL) ||
2574 	    ((propIter = scf_iter_create(handle)) == NULL) ||
2575 	    ((value = scf_value_create(handle)) == NULL)) {
2576 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2577 		    scf_strerror(scf_error()));
2578 		ret = STMF_PS_ERROR;
2579 		goto out;
2580 	}
2581 
2582 	/*
2583 	 * get group list property group
2584 	 */
2585 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
2586 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
2587 			ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
2588 		} else {
2589 			syslog(LOG_ERR, "get pg %s failed - %s",
2590 			    pgName, scf_strerror(scf_error()));
2591 			ret = STMF_PS_ERROR;
2592 		}
2593 		goto out;
2594 	}
2595 
2596 	/*
2597 	 * propIter is the iterator handle
2598 	 */
2599 	if (scf_iter_pg_properties(propIter, pg) == -1) {
2600 		syslog(LOG_ERR, "iter properties for %s failed - %s",
2601 		    pgName, scf_strerror(scf_error()));
2602 		ret = STMF_PS_ERROR;
2603 		goto out;
2604 	}
2605 
2606 	/*
2607 	 * Iterate through group properties searching for the requested
2608 	 * group name. When we find it, we need to get the property name
2609 	 * since it refers to the actual group name.
2610 	 */
2611 
2612 	/* initialize to not found */
2613 	ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
2614 	while (scf_iter_next_property(propIter, prop) == 1) {
2615 		if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) {
2616 			syslog(LOG_ERR, "get name from %s iter failed - %s",
2617 			    pgName, scf_strerror(scf_error()));
2618 			ret = STMF_PS_ERROR;
2619 			break;
2620 		}
2621 		/*
2622 		 * Skip over non-member list properties
2623 		 */
2624 		if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) {
2625 			continue;
2626 		}
2627 		if (scf_property_get_value(prop, value) == -1) {
2628 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
2629 			    pgName, actualName, scf_strerror(scf_error()));
2630 			ret = STMF_PS_ERROR;
2631 			break;
2632 		}
2633 		if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
2634 			syslog(LOG_ERR, "get ustring %s/%s failed - %s",
2635 			    pgName, actualName, scf_strerror(scf_error()));
2636 			ret = STMF_PS_ERROR;
2637 			break;
2638 		}
2639 
2640 		/*
2641 		 * When we find a match, set success and break
2642 		 */
2643 		if ((strlen(buf) == strlen(groupName)) &&
2644 		    bcmp(buf, groupName, strlen(buf)) == 0) {
2645 			ret = STMF_PS_SUCCESS;
2646 			break;
2647 		}
2648 	}
2649 
2650 	/*
2651 	 * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND
2652 	 */
2653 
2654 out:
2655 	/*
2656 	 * Free resources
2657 	 */
2658 	if (handle != NULL) {
2659 		scf_handle_destroy(handle);
2660 	}
2661 	if (svc != NULL) {
2662 		scf_service_destroy(svc);
2663 	}
2664 	if (pg != NULL) {
2665 		scf_pg_destroy(pg);
2666 	}
2667 	if (propIter != NULL) {
2668 		scf_iter_destroy(propIter);
2669 	}
2670 	if (prop != NULL) {
2671 		scf_property_destroy(prop);
2672 	}
2673 	if (value != NULL) {
2674 		scf_value_destroy(value);
2675 	}
2676 
2677 	return (ret);
2678 }
2679 
2680 /*
2681  * psAddHostGroupMember
2682  *
2683  * Add a host group member to a host group,
2684  *
2685  * Input: groupName - name of group to which the member is added
2686  *        memberName - name of group member to add
2687  */
2688 int
2689 psAddHostGroupMember(char *groupName, char *memberName)
2690 {
2691 	int ret;
2692 	char groupPropListName[MAXNAMELEN];
2693 	char groupPropName[MAXNAMELEN];
2694 
2695 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
2696 	    groupPropName);
2697 	if (ret != STMF_PS_SUCCESS) {
2698 		return (ret);
2699 	}
2700 
2701 	if (snprintf(groupPropListName, sizeof (groupPropListName),
2702 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
2703 	    sizeof (groupPropListName)) {
2704 		syslog(LOG_ERR, "buffer overflow on property name %s",
2705 		    groupPropName);
2706 		return (STMF_PS_ERROR);
2707 	}
2708 
2709 	return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
2710 	    memberName, ADD));
2711 }
2712 
2713 /*
2714  * psAddTargetGroupMember
2715  *
2716  * Add a target port group member to a target group
2717  *
2718  * Input: groupName - name of group to which the member is added
2719  *        memberName - name of group member to add. Must be nul terminated.
2720  */
2721 int
2722 psAddTargetGroupMember(char *groupName, char *memberName)
2723 {
2724 	int ret;
2725 	char groupPropListName[MAXNAMELEN];
2726 	char groupPropName[MAXNAMELEN];
2727 
2728 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
2729 	    groupPropName);
2730 	if (ret != STMF_PS_SUCCESS) {
2731 		return (ret);
2732 	}
2733 
2734 	if (snprintf(groupPropListName, sizeof (groupPropListName),
2735 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
2736 	    sizeof (groupPropListName)) {
2737 		syslog(LOG_ERR, "buffer overflow on property name %s",
2738 		    groupPropName);
2739 		return (STMF_PS_ERROR);
2740 	}
2741 
2742 	return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
2743 	    memberName, ADD));
2744 }
2745 
2746 
2747 /*
2748  * psAddViewEntry
2749  *
2750  * luGuid - logical unit identifier
2751  * viewEntry - pointer to viewEntry allocated by the caller that contains
2752  *             the values to set for this view entry
2753  *
2754  * returns:
2755  *  STMF_PS_SUCCESS on success
2756  *  STMF_PS_ERROR_* on failure
2757  */
2758 int
2759 psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
2760 {
2761 	scf_handle_t	*handle = NULL;
2762 	scf_service_t	*svc = NULL;
2763 	scf_propertygroup_t	*pg = NULL;
2764 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
2765 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
2766 	char scfLuPgName[LOGICAL_UNIT_PG_SIZE];
2767 	int ret = STMF_PS_SUCCESS;
2768 	sigset_t sigmaskRestore;
2769 
2770 	/* grab the signal hold lock */
2771 	(void) pthread_mutex_lock(&sigSetLock);
2772 
2773 	/*
2774 	 * hold signals until we're done
2775 	 */
2776 	if (holdSignal(&sigmaskRestore) != 0) {
2777 		(void) pthread_mutex_unlock(&sigSetLock);
2778 		return (STMF_PS_ERROR);
2779 	}
2780 
2781 	ret = iPsInit(&handle, &svc);
2782 	if (ret != STMF_PS_SUCCESS) {
2783 		goto out;
2784 	}
2785 
2786 	pg = scf_pg_create(handle);
2787 	if (pg == NULL) {
2788 		syslog(LOG_ERR, "scf pg alloc failed - %s",
2789 		    scf_strerror(scf_error()));
2790 		ret = STMF_PS_ERROR;
2791 		goto out;
2792 	}
2793 
2794 	/* Convert to ASCII uppercase hexadecimal string */
2795 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
2796 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
2797 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
2798 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
2799 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
2800 	    lu->guid[14], lu->guid[15]);
2801 
2802 	(void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s",
2803 	    STMF_LU_PREFIX, guidAsciiBuf);
2804 
2805 	bzero(viewEntryPgName, sizeof (viewEntryPgName));
2806 	/*
2807 	 * Format of view entry property group name:
2808 	 *	VE-<view_entry_name>-<lu_name>
2809 	 */
2810 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
2811 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf);
2812 
2813 	ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry);
2814 
2815 out:
2816 	/*
2817 	 * Okay, we're done. Release the signals
2818 	 */
2819 	if (releaseSignal(&sigmaskRestore) != 0) {
2820 		/*
2821 		 * Don't set this as an STMF_PS_ERROR_*. We succeeded
2822 		 * the requested operation. But we do need to log it.
2823 		 */
2824 		syslog(LOG_ERR, "Unable to release one or more signals - %s",
2825 		    strerror(errno));
2826 	}
2827 
2828 	/*
2829 	 * Free resources
2830 	 */
2831 	if (handle != NULL) {
2832 		scf_handle_destroy(handle);
2833 	}
2834 	if (svc != NULL) {
2835 		scf_service_destroy(svc);
2836 	}
2837 	if (pg != NULL) {
2838 		scf_pg_destroy(pg);
2839 	}
2840 
2841 	/* release the signal hold lock */
2842 	(void) pthread_mutex_unlock(&sigSetLock);
2843 
2844 	return (ret);
2845 }
2846 
2847 /*
2848  * psCheckService
2849  *
2850  * Purpose: Checks whether service exists
2851  *
2852  */
2853 int
2854 psCheckService()
2855 {
2856 	int ret;
2857 	scf_handle_t	*handle = NULL;
2858 	scf_service_t	*svc = NULL;
2859 
2860 	ret = iPsInit(&handle, &svc);
2861 
2862 	/*
2863 	 * Free resources
2864 	 */
2865 	if (handle != NULL) {
2866 		scf_handle_destroy(handle);
2867 	}
2868 	if (svc != NULL) {
2869 		scf_service_destroy(svc);
2870 	}
2871 
2872 	return (ret);
2873 }
2874 
2875 /*
2876  * psCreateHostGroup
2877  *
2878  * groupName - name of group to create
2879  *
2880  * returns:
2881  *  STMF_PS_SUCCESS on success
2882  *  STMF_PS_ERROR_* on failure
2883  */
2884 int
2885 psCreateHostGroup(char *groupName)
2886 {
2887 	return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD));
2888 }
2889 
2890 /*
2891  * psCreateTargetGroup
2892  *
2893  * groupName - name of group to create
2894  *
2895  * returns:
2896  *  STMF_PS_SUCCESS on success
2897  *  STMF_PS_ERROR_* on failure
2898  */
2899 int
2900 psCreateTargetGroup(char *groupName)
2901 {
2902 	return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD));
2903 }
2904 
2905 /*
2906  * psDeleteHostGroup
2907  *
2908  * groupName - name of group to delete
2909  *
2910  * returns:
2911  *  STMF_PS_SUCCESS on success
2912  *  STMF_PS_ERROR_* on failure
2913  */
2914 int
2915 psDeleteHostGroup(char *groupName)
2916 {
2917 	return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE));
2918 }
2919 
2920 /*
2921  * psDeleteTargetGroup
2922  *
2923  * groupName - name of group to delete
2924  *
2925  * returns:
2926  *  STMF_PS_SUCCESS on success
2927  *  STMF_PS_ERROR_* on failure
2928  */
2929 int
2930 psDeleteTargetGroup(char *groupName)
2931 {
2932 	return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName,
2933 	    REMOVE));
2934 }
2935 
2936 /*
2937  * psGetHostGroupList
2938  *
2939  * groupList - pointer to pointer to stmfGroupList. Contains the list
2940  *             of host groups on successful return.
2941  *
2942  * returns:
2943  *  STMF_PS_SUCCESS on success
2944  *  STMF_PS_ERROR_* on failure
2945  */
2946 int
2947 psGetHostGroupList(stmfGroupList **groupList)
2948 {
2949 	return (iPsGetGroupList(STMF_HOST_GROUPS, groupList));
2950 }
2951 
2952 /*
2953  * psGetLogicalUnitList
2954  *
2955  *
2956  */
2957 int
2958 psGetLogicalUnitList(stmfGuidList **guidList)
2959 {
2960 	scf_handle_t	*handle = NULL;
2961 	scf_service_t	*svc = NULL;
2962 	scf_propertygroup_t	*pg = NULL;
2963 	scf_iter_t	*pgIter = NULL;
2964 	char buf[MAXNAMELEN];
2965 	int guidCnt = 0;
2966 	int i = 0, j;
2967 	int ret = STMF_PS_SUCCESS;
2968 	unsigned int guid[sizeof (stmfGuid)];
2969 	stmfGuid outGuid;
2970 
2971 	assert(guidList != NULL);
2972 
2973 	ret = iPsInit(&handle, &svc);
2974 	if (ret != STMF_PS_SUCCESS) {
2975 		goto out;
2976 	}
2977 
2978 	/*
2979 	 * Allocate scf resources
2980 	 */
2981 	if (((pg = scf_pg_create(handle)) == NULL) ||
2982 	    ((pgIter = scf_iter_create(handle)) == NULL)) {
2983 		syslog(LOG_ERR, "scf alloc resource failed - %s",
2984 		    scf_strerror(scf_error()));
2985 		ret = STMF_PS_ERROR;
2986 		goto out;
2987 	}
2988 
2989 	/*
2990 	 * pgIter is the iterator handle
2991 	 */
2992 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
2993 		syslog(LOG_ERR, "iter property groups failed - %s",
2994 		    scf_strerror(scf_error()));
2995 		ret = STMF_PS_ERROR;
2996 		goto out;
2997 	}
2998 
2999 	while (scf_iter_next_pg(pgIter, pg) == 1) {
3000 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
3001 			syslog(LOG_ERR, "get pg name failed - %s",
3002 			    scf_strerror(scf_error()));
3003 			ret = STMF_PS_ERROR;
3004 			break;
3005 		}
3006 		/*
3007 		 * Only count LU property groups
3008 		 */
3009 		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) {
3010 			guidCnt++;
3011 		}
3012 	}
3013 
3014 	/*
3015 	 * pgIter is the iterator handle
3016 	 */
3017 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
3018 		syslog(LOG_ERR, "iter property groups failed - %s",
3019 		    scf_strerror(scf_error()));
3020 		ret = STMF_PS_ERROR;
3021 		goto out;
3022 	}
3023 
3024 	*guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
3025 	    guidCnt * sizeof (stmfGuid));
3026 	if (*guidList == NULL) {
3027 		ret = STMF_PS_ERROR_NOMEM;
3028 		goto out;
3029 	}
3030 
3031 	/*
3032 	 * it's possible for entries to be added/removed while we're retrieving
3033 	 * the property groups. Just make sure we don't write beyond our
3034 	 * allocated buffer by checking to ensure i < guidCnt.
3035 	 */
3036 	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) {
3037 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
3038 			syslog(LOG_ERR, "get pg name failed - %s",
3039 			    scf_strerror(scf_error()));
3040 			ret = STMF_PS_ERROR;
3041 			break;
3042 		}
3043 		/*
3044 		 * Only use LU property groups
3045 		 */
3046 		if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) {
3047 			continue;
3048 		}
3049 
3050 		j = strlen(STMF_LU_PREFIX) + strlen("-");
3051 
3052 		(void) sscanf(buf + j,
3053 		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
3054 		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
3055 		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
3056 		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
3057 
3058 		for (j = 0; j < sizeof (stmfGuid); j++) {
3059 			outGuid.guid[j] = guid[j];
3060 		}
3061 
3062 		bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid));
3063 		(*guidList)->cnt++;
3064 	}
3065 
3066 	if (ret != STMF_PS_SUCCESS) {
3067 		free(*guidList);
3068 		goto out;
3069 	}
3070 
3071 out:
3072 	/*
3073 	 * Free resources
3074 	 */
3075 	if (handle != NULL) {
3076 		scf_handle_destroy(handle);
3077 	}
3078 	if (svc != NULL) {
3079 		scf_service_destroy(svc);
3080 	}
3081 	if (pg != NULL) {
3082 		scf_pg_destroy(pg);
3083 	}
3084 	if (pgIter != NULL) {
3085 		scf_iter_destroy(pgIter);
3086 	}
3087 
3088 	return (ret);
3089 }
3090 
3091 /*
3092  * psGetTargetGroupList
3093  *
3094  * groupList - pointer to pointer to stmfGroupList. Contains the list
3095  *             of target groups on successful return.
3096  *
3097  * returns:
3098  *  STMF_PS_SUCCESS on success
3099  *  STMF_PS_ERROR_* on failure
3100  */
3101 int
3102 psGetTargetGroupList(stmfGroupList **groupList)
3103 {
3104 	return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList));
3105 }
3106 
3107 /*
3108  * psGetHostGroupMemberList
3109  *
3110  * groupName - group name for which to retrieve a member list
3111  * groupMemberList - pointer to pointer to stmfGroupProperties list
3112  *
3113  * returns:
3114  *  STMF_PS_SUCCESS on success
3115  *  STMF_PS_ERROR_* on failure
3116  */
3117 int
3118 psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList)
3119 {
3120 	int ret;
3121 	char groupPropListName[MAXNAMELEN];
3122 	char groupPropName[MAXNAMELEN];
3123 
3124 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
3125 	    groupPropName);
3126 	if (ret != STMF_PS_SUCCESS) {
3127 		return (ret);
3128 	}
3129 
3130 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3131 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3132 	    sizeof (groupPropListName)) {
3133 		syslog(LOG_ERR, "buffer overflow on property name %s",
3134 		    groupPropName);
3135 		return (STMF_PS_ERROR);
3136 	}
3137 
3138 	return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName,
3139 	    groupMemberList));
3140 }
3141 
3142 /*
3143  * psGetTargetGroupMemberList
3144  *
3145  * groupName - group name for which to retrieve a member list
3146  * groupMemberList - pointer to pointer to stmfGroupProperties list
3147  *
3148  * returns:
3149  *  STMF_PS_SUCCESS on success
3150  *  STMF_PS_ERROR_* on failure
3151  */
3152 int
3153 psGetTargetGroupMemberList(char *groupName,
3154     stmfGroupProperties **groupMemberList)
3155 {
3156 	int ret;
3157 	char groupPropListName[MAXNAMELEN];
3158 	char groupPropName[MAXNAMELEN];
3159 
3160 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
3161 	    groupPropName);
3162 	if (ret != STMF_PS_SUCCESS) {
3163 		return (ret);
3164 	}
3165 
3166 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3167 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3168 	    sizeof (groupPropListName)) {
3169 		syslog(LOG_ERR, "buffer overflow on property name %s",
3170 		    groupPropName);
3171 		return (STMF_PS_ERROR);
3172 	}
3173 
3174 	return (iPsGetGroupMemberList(STMF_TARGET_GROUPS,
3175 	    groupPropListName, groupMemberList));
3176 }
3177 
3178 /*
3179  * qsort function
3180  * sort on veIndex
3181  */
3182 static int
3183 viewEntryCompare(const void *p1, const void *p2)
3184 {
3185 
3186 	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
3187 	if (v1->veIndex > v2->veIndex)
3188 		return (1);
3189 	if (v1->veIndex < v2->veIndex)
3190 		return (-1);
3191 	return (0);
3192 }
3193 
3194 /*
3195  * psGetViewEntryList
3196  *
3197  * luGuid - identifier of logical unit for which to retrieve a view entry list
3198  * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated
3199  *                 on successful return.
3200  *
3201  * returns:
3202  *  STMF_PS_SUCCESS on success
3203  *  STMF_PS_ERROR_* on failure
3204  */
3205 int
3206 psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
3207 {
3208 	scf_handle_t	*handle = NULL;
3209 	scf_service_t	*svc = NULL;
3210 	scf_propertygroup_t	*pg = NULL;
3211 	scf_property_t	*prop = NULL;
3212 	scf_value_t *value = NULL;
3213 	scf_iter_t  *propIter = NULL;
3214 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
3215 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
3216 	char luPgName[LOGICAL_UNIT_PG_SIZE];
3217 	int ret = STMF_PS_SUCCESS;
3218 	uint64_t i = 0;
3219 	uint64_t veCnt;
3220 
3221 
3222 	ret = iPsInit(&handle, &svc);
3223 	if (ret != STMF_PS_SUCCESS) {
3224 		goto out;
3225 	}
3226 
3227 	/*
3228 	 * Allocate scf resources
3229 	 */
3230 	if (((pg = scf_pg_create(handle)) == NULL) ||
3231 	    ((prop = scf_property_create(handle)) == NULL) ||
3232 	    ((propIter = scf_iter_create(handle)) == NULL) ||
3233 	    ((value = scf_value_create(handle)) == NULL)) {
3234 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3235 		    scf_strerror(scf_error()));
3236 		ret = STMF_PS_ERROR;
3237 		goto out;
3238 	}
3239 
3240 	/* Convert to ASCII uppercase hexadecimal string */
3241 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
3242 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
3243 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
3244 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
3245 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
3246 	    lu->guid[14], lu->guid[15]);
3247 
3248 	/* form the LU property group name (LU-<guid>) */
3249 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
3250 	    STMF_LU_PREFIX, guidAsciiBuf);
3251 
3252 	/* get the property group associated with this LU */
3253 	if (scf_service_get_pg(svc, luPgName, pg) == -1) {
3254 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
3255 			ret = STMF_PS_ERROR_NOT_FOUND;
3256 		} else {
3257 			syslog(LOG_ERR, "get pg %s failed - %s",
3258 			    luPgName, scf_strerror(scf_error()));
3259 			ret = STMF_PS_ERROR;
3260 		}
3261 		goto out;
3262 	}
3263 
3264 	/* get the view entry count property */
3265 	if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
3266 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3267 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3268 		ret = STMF_PS_ERROR;
3269 		goto out;
3270 	}
3271 
3272 	if (scf_property_get_value(prop, value) == -1) {
3273 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3274 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3275 		ret = STMF_PS_ERROR;
3276 		goto out;
3277 	}
3278 
3279 	/*
3280 	 * Get the actual value of the view entry count property
3281 	 */
3282 	if (scf_value_get_count(value, &veCnt) == -1) {
3283 		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
3284 		    luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
3285 		ret = STMF_PS_ERROR;
3286 		goto out;
3287 	}
3288 
3289 	/*
3290 	 * propIter is the iterator handle
3291 	 */
3292 	if (scf_iter_pg_properties(propIter, pg) == -1) {
3293 		syslog(LOG_ERR, "iter properties for %s failed - %s",
3294 		    luPgName, scf_strerror(scf_error()));
3295 		ret = STMF_PS_ERROR;
3296 		goto out;
3297 	}
3298 
3299 	/*
3300 	 * alloc the list based on the view entry count
3301 	 */
3302 	*viewEntryList = (stmfViewEntryList *)calloc(1,
3303 	    sizeof (stmfViewEntryList) + veCnt * sizeof (stmfViewEntry));
3304 	if (*viewEntryList == NULL) {
3305 		ret = STMF_PS_ERROR_NOMEM;
3306 		goto out;
3307 	}
3308 
3309 	i = 0;
3310 	/*
3311 	 * iterate through the view entry properties to find the
3312 	 * view entries
3313 	 */
3314 	while (scf_iter_next_property(propIter, prop) == 1) {
3315 		/* find match for view entry property */
3316 		if (scf_property_get_name(prop, viewEntryPgName,
3317 		    sizeof (viewEntryPgName)) != -1) {
3318 			if (strncmp(viewEntryPgName, STMF_VE_PREFIX,
3319 			    strlen(STMF_VE_PREFIX)) != 0) {
3320 				continue;
3321 			}
3322 			/*
3323 			 * We've exceeded our alloc limit
3324 			 * break with error
3325 			 */
3326 			if (i == veCnt) {
3327 				ret = STMF_PS_ERROR;
3328 				break;
3329 			}
3330 
3331 			if ((ret = iPsGetViewEntry(viewEntryPgName,
3332 			    &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) {
3333 				break;
3334 			}
3335 
3336 			i++;
3337 
3338 			/* set the list count */
3339 			(*viewEntryList)->cnt++;
3340 		} else {
3341 			syslog(LOG_ERR, "scf iter %s properties failed - %s",
3342 			    luPgName, scf_strerror(scf_error()));
3343 			ret = STMF_PS_ERROR;
3344 			break;
3345 		}
3346 
3347 	}
3348 
3349 	if (ret != STMF_PS_SUCCESS) {
3350 		free(*viewEntryList);
3351 		goto out;
3352 	}
3353 
3354 	/*
3355 	 * We're sorting the final list here based on the veIndex
3356 	 * If we don't, the caller is going to have to do it to reap
3357 	 * some intelligent output.
3358 	 */
3359 	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
3360 	    sizeof (stmfViewEntry), viewEntryCompare);
3361 
3362 out:
3363 	/*
3364 	 * Free resources
3365 	 */
3366 	if (handle != NULL) {
3367 		scf_handle_destroy(handle);
3368 	}
3369 	if (svc != NULL) {
3370 		scf_service_destroy(svc);
3371 	}
3372 	if (pg != NULL) {
3373 		scf_pg_destroy(pg);
3374 	}
3375 	if (prop != NULL) {
3376 		scf_property_destroy(prop);
3377 	}
3378 	if (value != NULL) {
3379 		scf_value_destroy(value);
3380 	}
3381 	if (propIter != NULL) {
3382 		scf_iter_destroy(propIter);
3383 	}
3384 
3385 	return (ret);
3386 }
3387 
3388 /*
3389  * iPsGetViewEntry
3390  *
3391  * viewEntryPgName - view entry property group name to retrieve
3392  * viewEntry - pointer to stmfViewEntry structure allocated by the caller
3393  *
3394  * returns:
3395  *  STMF_PS_SUCCESS on success
3396  *  STMF_PS_ERROR_* on failure
3397  */
3398 static int
3399 iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry)
3400 {
3401 	scf_handle_t	*handle = NULL;
3402 	scf_service_t	*svc = NULL;
3403 	scf_propertygroup_t	*pg = NULL;
3404 	scf_property_t	*prop = NULL;
3405 	scf_value_t *value = NULL;
3406 	uint8_t scfBool;
3407 	char *indexPtr;
3408 	char groupName[sizeof (stmfGroupName)];
3409 	int ret = STMF_PS_SUCCESS;
3410 
3411 
3412 	ret = iPsInit(&handle, &svc);
3413 	if (ret != STMF_PS_SUCCESS) {
3414 		goto out;
3415 	}
3416 
3417 	/*
3418 	 * Allocate scf resources
3419 	 */
3420 	if (((pg = scf_pg_create(handle)) == NULL) ||
3421 	    ((prop = scf_property_create(handle)) == NULL) ||
3422 	    ((value = scf_value_create(handle)) == NULL)) {
3423 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3424 		    scf_strerror(scf_error()));
3425 		ret = STMF_PS_ERROR;
3426 		goto out;
3427 	}
3428 
3429 	bzero(viewEntry, sizeof (stmfViewEntry));
3430 
3431 	/*
3432 	 * get the service property group view entry handle
3433 	 */
3434 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
3435 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
3436 			ret = STMF_PS_ERROR_NOT_FOUND;
3437 		} else {
3438 			syslog(LOG_ERR, "get pg %s failed - %s",
3439 			    viewEntryPgName, scf_strerror(scf_error()));
3440 			ret = STMF_PS_ERROR;
3441 		}
3442 		goto out;
3443 	}
3444 
3445 
3446 	/*
3447 	 * get index
3448 	 * format is: VE-<veIndex>-GUID
3449 	 */
3450 	indexPtr = strchr(viewEntryPgName, '-');
3451 	if (!indexPtr) {
3452 		ret = STMF_PS_ERROR;
3453 		goto out;
3454 	}
3455 
3456 	/* Set the index */
3457 	viewEntry->veIndex = atoi(strtok(++indexPtr, "-"));
3458 
3459 	viewEntry->veIndexValid = B_TRUE;
3460 
3461 	/* get allHosts property */
3462 	if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS,
3463 	    prop) == -1) {
3464 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3465 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3466 		    scf_strerror(scf_error()));
3467 		ret = STMF_PS_ERROR;
3468 		goto out;
3469 	}
3470 
3471 	if (scf_property_get_value(prop, value) == -1) {
3472 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3473 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3474 		    scf_strerror(scf_error()));
3475 		ret = STMF_PS_ERROR;
3476 		goto out;
3477 	}
3478 
3479 	/* set allHosts */
3480 	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
3481 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3482 		    viewEntryPgName, STMF_VE_ALLHOSTS,
3483 		    scf_strerror(scf_error()));
3484 		ret = STMF_PS_ERROR;
3485 		goto out;
3486 	}
3487 	viewEntry->allHosts = scfBool;
3488 
3489 	/* get hostGroup property */
3490 	if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP,
3491 	    prop) == -1) {
3492 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3493 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3494 		    scf_strerror(scf_error()));
3495 		ret = STMF_PS_ERROR;
3496 		goto out;
3497 	}
3498 
3499 	if (scf_property_get_value(prop, value) == -1) {
3500 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3501 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3502 		    scf_strerror(scf_error()));
3503 		ret = STMF_PS_ERROR;
3504 		goto out;
3505 	}
3506 
3507 	if (scf_value_get_ustring(value, groupName,
3508 	    sizeof (groupName)) == -1) {
3509 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3510 		    viewEntryPgName, STMF_VE_HOSTGROUP,
3511 		    scf_strerror(scf_error()));
3512 		ret = STMF_PS_ERROR;
3513 		goto out;
3514 	}
3515 	/* set hostGroup */
3516 	bcopy(groupName, viewEntry->hostGroup, strlen(groupName));
3517 
3518 	/* get allTargets property */
3519 	if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS,
3520 	    prop) == -1) {
3521 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3522 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3523 		    scf_strerror(scf_error()));
3524 		ret = STMF_PS_ERROR;
3525 		goto out;
3526 	}
3527 
3528 	if (scf_property_get_value(prop, value) == -1) {
3529 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3530 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3531 		    scf_strerror(scf_error()));
3532 		ret = STMF_PS_ERROR;
3533 		goto out;
3534 	}
3535 
3536 	/* set allTargets */
3537 	if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
3538 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3539 		    viewEntryPgName, STMF_VE_ALLTARGETS,
3540 		    scf_strerror(scf_error()));
3541 		ret = STMF_PS_ERROR;
3542 		goto out;
3543 	}
3544 	viewEntry->allTargets = scfBool;
3545 
3546 	/* get targetGroup property */
3547 	if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) {
3548 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3549 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3550 		    scf_strerror(scf_error()));
3551 		ret = STMF_PS_ERROR;
3552 		goto out;
3553 	}
3554 
3555 	if (scf_property_get_value(prop, value) == -1) {
3556 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3557 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3558 		    scf_strerror(scf_error()));
3559 		ret = STMF_PS_ERROR;
3560 		goto out;
3561 	}
3562 
3563 	if (scf_value_get_ustring(value, groupName,
3564 	    sizeof (groupName)) == -1) {
3565 		syslog(LOG_ERR, "get value %s/%s failed - %s",
3566 		    viewEntryPgName, STMF_VE_TARGETGROUP,
3567 		    scf_strerror(scf_error()));
3568 		ret = STMF_PS_ERROR;
3569 		goto out;
3570 	}
3571 	/* set targetGroup */
3572 	bcopy(groupName, viewEntry->targetGroup, strlen(groupName));
3573 
3574 	/* get luNbr property */
3575 	if (scf_pg_get_property(pg, STMF_VE_LUNBR,
3576 	    prop) == -1) {
3577 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3578 		    viewEntryPgName, STMF_VE_LUNBR,
3579 		    scf_strerror(scf_error()));
3580 		ret = STMF_PS_ERROR;
3581 		goto out;
3582 	}
3583 
3584 	if (scf_property_get_value(prop, value) == -1) {
3585 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3586 		    viewEntryPgName, STMF_VE_LUNBR,
3587 		    scf_strerror(scf_error()));
3588 		ret = STMF_PS_ERROR;
3589 		goto out;
3590 	}
3591 
3592 	/* set luNbr */
3593 	if (scf_value_get_opaque(value, (char *)viewEntry->luNbr,
3594 	    sizeof (viewEntry->luNbr)) == -1) {
3595 		syslog(LOG_ERR, "get opaque value %s/%s failed - %s",
3596 		    viewEntryPgName, STMF_VE_LUNBR,
3597 		    scf_strerror(scf_error()));
3598 		ret = STMF_PS_ERROR;
3599 		goto out;
3600 	}
3601 	/* set luNbrValid to true since we just got it */
3602 	viewEntry->luNbrValid = B_TRUE;
3603 
3604 out:
3605 	/*
3606 	 * Free resources
3607 	 */
3608 	if (handle != NULL) {
3609 		scf_handle_destroy(handle);
3610 	}
3611 	if (svc != NULL) {
3612 		scf_service_destroy(svc);
3613 	}
3614 	if (pg != NULL) {
3615 		scf_pg_destroy(pg);
3616 	}
3617 	if (value != NULL) {
3618 		scf_value_destroy(value);
3619 	}
3620 	if (prop != NULL) {
3621 		scf_property_destroy(prop);
3622 	}
3623 
3624 	return (ret);
3625 }
3626 
3627 
3628 /*
3629  * psRemoveHostGroupMember
3630  *
3631  * Remove a host group member from a host group,
3632  *
3633  * groupName - name of group from which the member is removed
3634  * memberName - name of group member to remove
3635  *
3636  * returns:
3637  *  STMF_PS_SUCCESS on success
3638  *  STMF_PS_ERROR_* on failure
3639  */
3640 int
3641 psRemoveHostGroupMember(char *groupName, char *memberName)
3642 {
3643 	int ret;
3644 	char groupPropListName[MAXNAMELEN];
3645 	char groupPropName[MAXNAMELEN];
3646 
3647 	ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
3648 	    groupPropName);
3649 	if (ret != STMF_PS_SUCCESS) {
3650 		return (ret);
3651 	}
3652 
3653 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3654 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3655 	    sizeof (groupPropListName)) {
3656 		syslog(LOG_ERR, "buffer overflow on property name %s",
3657 		    groupPropName);
3658 		return (STMF_PS_ERROR);
3659 	}
3660 
3661 	return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
3662 	    memberName, REMOVE));
3663 }
3664 
3665 /*
3666  * psRemoveTargetGroupMember
3667  *
3668  * Remove a target port group member from an target port group,
3669  *
3670  * groupName - name of group from which the member is removed
3671  * memberName - name of group member to remove
3672  *
3673  * returns:
3674  *  STMF_PS_SUCCESS on success
3675  *  STMF_PS_ERROR_* on failure
3676  */
3677 int
3678 psRemoveTargetGroupMember(char *groupName, char *memberName)
3679 {
3680 	int ret;
3681 	char groupPropListName[MAXNAMELEN];
3682 	char groupPropName[MAXNAMELEN];
3683 
3684 	ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
3685 	    groupPropName);
3686 	if (ret != STMF_PS_SUCCESS) {
3687 		return (ret);
3688 	}
3689 
3690 	if (snprintf(groupPropListName, sizeof (groupPropListName),
3691 	    "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
3692 	    sizeof (groupPropListName)) {
3693 		syslog(LOG_ERR, "buffer overflow on property name %s",
3694 		    groupPropName);
3695 		return (STMF_PS_ERROR);
3696 	}
3697 
3698 	return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
3699 	    memberName, REMOVE));
3700 }
3701 
3702 /*
3703  * psGetProviderData
3704  *
3705  * Retrieves an nvlist on a per provider basis
3706  *
3707  * providerName - property group name to use
3708  * nvl - nvlist to retrieve
3709  *
3710  */
3711 int
3712 psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
3713     uint64_t *setToken)
3714 {
3715 	scf_handle_t	*handle = NULL;
3716 	scf_service_t	*svc = NULL;
3717 	scf_propertygroup_t	*pg = NULL;
3718 	scf_property_t	*prop = NULL;
3719 	scf_value_t	*value = NULL;
3720 	uint64_t blockCnt = 0;
3721 	ssize_t blockOffset = 0;
3722 	ssize_t actualBlockSize = 0;
3723 	char pgName[MAXPATHLEN];
3724 	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
3725 	char *nvlistEncoded = NULL;
3726 	ssize_t nvlistEncodedSize = 0;
3727 	boolean_t foundSetCnt = B_TRUE;
3728 	int i;
3729 	int ret = STMF_PS_SUCCESS;
3730 
3731 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
3732 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
3733 		ret = STMF_PS_ERROR_INVALID_ARG;
3734 		goto out;
3735 	}
3736 
3737 	ret = iPsInit(&handle, &svc);
3738 	if (ret != STMF_PS_SUCCESS) {
3739 		goto out;
3740 	}
3741 
3742 	/*
3743 	 * create the property group name
3744 	 */
3745 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
3746 	    STMF_PROVIDER_DATA_PREFIX, providerName);
3747 
3748 	/*
3749 	 * Allocate scf resources
3750 	 */
3751 	if (((pg = scf_pg_create(handle)) == NULL) ||
3752 	    ((value = scf_value_create(handle)) == NULL) ||
3753 	    ((prop = scf_property_create(handle)) == NULL)) {
3754 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3755 		    scf_strerror(scf_error()));
3756 		ret = STMF_PS_ERROR;
3757 		goto out;
3758 	}
3759 
3760 	/*
3761 	 * Retrieve the existing property group.
3762 	 */
3763 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
3764 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
3765 			syslog(LOG_ERR, "get pg %s failed - %s", pgName,
3766 			    scf_strerror(scf_error()));
3767 			ret = STMF_PS_ERROR;
3768 			goto out;
3769 		} else {
3770 			ret = STMF_PS_ERROR_NOT_FOUND;
3771 			goto out;
3772 		}
3773 	}
3774 
3775 	/*
3776 	 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
3777 	 */
3778 	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
3779 	    prop) == -1) {
3780 		syslog(LOG_ERR, "get property %s/%s failed - %s",
3781 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
3782 		    scf_strerror(scf_error()));
3783 		ret = STMF_PS_ERROR;
3784 		goto out;
3785 	}
3786 
3787 	/*
3788 	 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
3789 	 */
3790 	if (scf_property_get_value(prop, value) == -1) {
3791 		syslog(LOG_ERR, "get property value %s/%s failed - %s",
3792 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
3793 		    scf_strerror(scf_error()));
3794 		ret = STMF_PS_ERROR;
3795 		goto out;
3796 	}
3797 
3798 	/*
3799 	 * Now get the actual value from the value handle
3800 	 */
3801 	if (scf_value_get_count(value, &blockCnt) == -1) {
3802 		syslog(LOG_ERR, "get integer value %s/%s failed - %s",
3803 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
3804 		    scf_strerror(scf_error()));
3805 		ret = STMF_PS_ERROR;
3806 		goto out;
3807 	}
3808 
3809 	/* Has the caller requested the token to be set? */
3810 	if (setToken) {
3811 		/*
3812 		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
3813 		 * If it doesn't exist, we assume it to be zero.
3814 		 */
3815 		*setToken = 0;
3816 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
3817 		    prop) == -1) {
3818 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
3819 				foundSetCnt = B_FALSE;
3820 			} else {
3821 				syslog(LOG_ERR, "get property %s/%s "
3822 				    "failed - %s", pgName,
3823 				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
3824 				    scf_strerror(scf_error()));
3825 				ret = STMF_PS_ERROR;
3826 				goto out;
3827 			}
3828 		}
3829 
3830 		if (foundSetCnt) {
3831 			/*
3832 			 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
3833 			 */
3834 			if (scf_property_get_value(prop, value) == -1) {
3835 				syslog(LOG_ERR,
3836 				    "get property value %s/%s failed - %s",
3837 				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
3838 				    scf_strerror(scf_error()));
3839 				ret = STMF_PS_ERROR;
3840 				goto out;
3841 			}
3842 
3843 			/*
3844 			 * Now get the actual value from the value handle
3845 			 * and set the caller's token
3846 			 */
3847 			if (scf_value_get_count(value, setToken) == -1) {
3848 				syslog(LOG_ERR,
3849 				    "get integer value %s/%s failed - %s",
3850 				    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
3851 				    scf_strerror(scf_error()));
3852 				ret = STMF_PS_ERROR;
3853 				goto out;
3854 			}
3855 		}
3856 	}
3857 
3858 	nvlistEncoded = (char *)calloc(1,
3859 	    blockCnt * STMF_PROVIDER_DATA_PROP_SIZE);
3860 	if (nvlistEncoded == NULL) {
3861 		syslog(LOG_ERR, "nvlistEncoded alloc failed");
3862 		ret = STMF_PS_ERROR_NOMEM;
3863 		goto out;
3864 	}
3865 
3866 	for (i = 0; i < blockCnt; i++) {
3867 		bzero(dataPropertyName, sizeof (dataPropertyName));
3868 		/*
3869 		 * create the name to use for the property
3870 		 */
3871 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
3872 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
3873 
3874 		if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) {
3875 			syslog(LOG_ERR, "get property %s/%s failed - %s",
3876 			    pgName, dataPropertyName,
3877 			    scf_strerror(scf_error()));
3878 			ret = STMF_PS_ERROR;
3879 			goto out;
3880 		}
3881 
3882 		if (scf_property_get_value(prop, value) == -1) {
3883 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
3884 			    pgName, dataPropertyName,
3885 			    scf_strerror(scf_error()));
3886 			ret = STMF_PS_ERROR;
3887 			goto out;
3888 		}
3889 
3890 		/*
3891 		 * Set the data block offset
3892 		 */
3893 		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
3894 		actualBlockSize = scf_value_get_opaque(value,
3895 		    &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE);
3896 		if (actualBlockSize == -1) {
3897 			syslog(LOG_ERR, "get opaque property value %s/%s "
3898 			    "failed - %s", pgName, dataPropertyName,
3899 			    scf_strerror(scf_error()));
3900 			ret = STMF_PS_ERROR;
3901 			goto out;
3902 		}
3903 		nvlistEncodedSize += actualBlockSize;
3904 	}
3905 
3906 	if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) {
3907 		syslog(LOG_ERR, "unable to unpack nvlist");
3908 		ret = STMF_PS_ERROR;
3909 		goto out;
3910 	}
3911 
3912 
3913 out:
3914 	/*
3915 	 * Free resources
3916 	 */
3917 	if (handle != NULL) {
3918 		scf_handle_destroy(handle);
3919 	}
3920 	if (svc != NULL) {
3921 		scf_service_destroy(svc);
3922 	}
3923 	if (pg != NULL) {
3924 		scf_pg_destroy(pg);
3925 	}
3926 	if (prop != NULL) {
3927 		scf_property_destroy(prop);
3928 	}
3929 	if (value != NULL) {
3930 		scf_value_destroy(value);
3931 	}
3932 	if (nvlistEncoded != NULL) {
3933 		free(nvlistEncoded);
3934 	}
3935 
3936 	return (ret);
3937 
3938 }
3939 /*
3940  * psGetProviderDataList
3941  *
3942  * Retrieves the list of providers that currently store persistent data
3943  *
3944  * providerList - pointer to a pointer to an stmfProviderList structure
3945  *                On success, this will contain the list of providers
3946  *                currently storing persistent data.
3947  */
3948 int
3949 psGetProviderDataList(stmfProviderList **providerList)
3950 {
3951 	scf_handle_t *handle = NULL;
3952 	scf_service_t *svc = NULL;
3953 	scf_propertygroup_t *pg = NULL;
3954 	scf_property_t *prop = NULL;
3955 	scf_value_t *value = NULL;
3956 	scf_iter_t *pgIter = NULL;
3957 	char buf[MAXNAMELEN];
3958 	int providerCnt = 0;
3959 	int64_t providerType;
3960 	int i = 0, j;
3961 	int ret = STMF_PS_SUCCESS;
3962 
3963 	ret = iPsInit(&handle, &svc);
3964 	if (ret != STMF_PS_SUCCESS) {
3965 		goto out;
3966 	}
3967 
3968 	*providerList = NULL;
3969 
3970 	/*
3971 	 * Allocate scf resources
3972 	 */
3973 	if (((pg = scf_pg_create(handle)) == NULL) ||
3974 	    ((value = scf_value_create(handle)) == NULL) ||
3975 	    ((prop = scf_property_create(handle)) == NULL) ||
3976 	    ((pgIter = scf_iter_create(handle)) == NULL)) {
3977 		syslog(LOG_ERR, "scf alloc resource failed - %s",
3978 		    scf_strerror(scf_error()));
3979 		ret = STMF_PS_ERROR;
3980 		goto out;
3981 	}
3982 
3983 	/*
3984 	 * pgIter is the iterator handle
3985 	 */
3986 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
3987 		syslog(LOG_ERR, "iter property groups failed - %s",
3988 		    scf_strerror(scf_error()));
3989 		ret = STMF_PS_ERROR;
3990 		goto out;
3991 	}
3992 
3993 	while (scf_iter_next_pg(pgIter, pg) == 1) {
3994 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
3995 			syslog(LOG_ERR, "get name failed - %s",
3996 			    scf_strerror(scf_error()));
3997 			ret = STMF_PS_ERROR;
3998 			break;
3999 		}
4000 		/*
4001 		 * Only count LU property groups
4002 		 */
4003 		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
4004 		    strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) {
4005 			providerCnt++;
4006 		}
4007 	}
4008 
4009 	/*
4010 	 * pgIter is the iterator handle
4011 	 */
4012 	if (scf_iter_service_pgs(pgIter, svc) == -1) {
4013 		syslog(LOG_ERR, "iter property groups failed - %s",
4014 		    scf_strerror(scf_error()));
4015 		ret = STMF_PS_ERROR;
4016 		goto out;
4017 	}
4018 
4019 	*providerList = (stmfProviderList *)calloc(1,
4020 	    sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider));
4021 	if (*providerList == NULL) {
4022 		ret = STMF_PS_ERROR_NOMEM;
4023 		goto out;
4024 	}
4025 
4026 	/*
4027 	 * it's possible for entries to be added/removed while we're retrieving
4028 	 * the property groups. Just make sure we don't write beyond our
4029 	 * allocated buffer by checking to ensure i < providerCnt.
4030 	 */
4031 	while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) {
4032 		if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
4033 			syslog(LOG_ERR, "get name failed - %s",
4034 			    scf_strerror(scf_error()));
4035 			ret = STMF_PS_ERROR;
4036 			break;
4037 		}
4038 		/*
4039 		 * Only use provider data property groups
4040 		 */
4041 		if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
4042 		    strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) {
4043 			continue;
4044 		}
4045 
4046 		/*
4047 		 * Get the STMF_PROVIDER_DATA_PROP_TYPE property
4048 		 */
4049 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE,
4050 		    prop) == -1) {
4051 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4052 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4053 			    scf_strerror(scf_error()));
4054 			ret = STMF_PS_ERROR;
4055 			break;
4056 		}
4057 
4058 		/*
4059 		 * Get the STMF_PROVIDER_DATA_PROP_TYPE value
4060 		 */
4061 		if (scf_property_get_value(prop, value) == -1) {
4062 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4063 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4064 			    scf_strerror(scf_error()));
4065 			ret = STMF_PS_ERROR;
4066 			break;
4067 		}
4068 
4069 		/*
4070 		 * Now get the actual value from the value handle
4071 		 */
4072 		if (scf_value_get_integer(value, &providerType) == -1) {
4073 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4074 			    buf, STMF_PROVIDER_DATA_PROP_TYPE,
4075 			    scf_strerror(scf_error()));
4076 			ret = STMF_PS_ERROR;
4077 			break;
4078 		}
4079 
4080 		(*providerList)->provider[i].providerType = providerType;
4081 
4082 		/* determine offset for copy of provider name */
4083 		j = strlen(STMF_PROVIDER_DATA_PREFIX);
4084 
4085 		/* copy provider name to caller's list */
4086 		(void) strncpy((*providerList)->provider[i].name, buf + j,
4087 		    sizeof ((*providerList)->provider[i].name));
4088 		i++;
4089 		(*providerList)->cnt++;
4090 	}
4091 
4092 	if (ret != STMF_PS_SUCCESS) {
4093 		free(*providerList);
4094 		goto out;
4095 	}
4096 
4097 out:
4098 	/*
4099 	 * Free resources
4100 	 */
4101 	if (handle != NULL) {
4102 		scf_handle_destroy(handle);
4103 	}
4104 	if (svc != NULL) {
4105 		scf_service_destroy(svc);
4106 	}
4107 	if (pg != NULL) {
4108 		scf_pg_destroy(pg);
4109 	}
4110 	if (value != NULL) {
4111 		scf_value_destroy(value);
4112 	}
4113 	if (prop != NULL) {
4114 		scf_property_destroy(prop);
4115 	}
4116 	if (pgIter != NULL) {
4117 		scf_iter_destroy(pgIter);
4118 	}
4119 
4120 	return (ret);
4121 }
4122 
4123 
4124 /*
4125  * psSetProviderData
4126  *
4127  * Stores a packed nvlist on a per provider basis
4128  *
4129  * providerName - property group name to use
4130  * nvl - nvlist to store
4131  * providerType - type of provider (logical unit or port)
4132  *
4133  */
4134 int
4135 psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
4136     uint64_t *setToken)
4137 {
4138 	scf_handle_t	*handle = NULL;
4139 	scf_service_t	*svc = NULL;
4140 	scf_propertygroup_t	*pg = NULL;
4141 	scf_property_t	*prop = NULL;
4142 	scf_transaction_t *tran = NULL;
4143 	/* represents arrays of entry and value pointers for scf */
4144 	scf_transaction_entry_t	**addEntry = NULL;
4145 	scf_transaction_entry_t	**deleteEntry = NULL;
4146 	scf_value_t **addValue = NULL;
4147 
4148 	/*
4149 	 * These declarations are for known entry and value set/get
4150 	 * operations
4151 	 */
4152 	scf_transaction_entry_t *entry1 = NULL;
4153 	scf_transaction_entry_t *entry2 = NULL;
4154 	scf_transaction_entry_t *entry3 = NULL;
4155 	scf_transaction_entry_t *entry5 = NULL;
4156 	scf_value_t *value1 = NULL;
4157 	scf_value_t *value2 = NULL;
4158 	scf_value_t *value3 = NULL;
4159 	scf_value_t *value4 = NULL;
4160 	scf_value_t *value5 = NULL;
4161 
4162 	boolean_t newPg = B_FALSE;
4163 	char pgName[MAXPATHLEN];
4164 	char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
4165 	char *nvlistEncoded = NULL;
4166 	size_t nvlistEncodedSize;
4167 	size_t blockSize;
4168 	int i, j = 0;
4169 	int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0;
4170 	int blockOffset;
4171 	uint64_t oldBlockCnt = 0;
4172 	uint64_t blockCnt = 0;
4173 	uint64_t setCnt = 0;
4174 	boolean_t foundSetCnt = B_TRUE;
4175 	int ret = STMF_PS_SUCCESS;
4176 	int commitRet;
4177 
4178 	if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
4179 	    providerType != STMF_PORT_PROVIDER_TYPE)) {
4180 		ret = STMF_PS_ERROR_INVALID_ARG;
4181 		goto out;
4182 	}
4183 
4184 	ret = iPsInit(&handle, &svc);
4185 	if (ret != STMF_PS_SUCCESS) {
4186 		goto out;
4187 	}
4188 
4189 	bzero(pgName, sizeof (pgName));
4190 	/*
4191 	 * create the property group name
4192 	 */
4193 	(void) snprintf(pgName, sizeof (pgName), "%s%s",
4194 	    STMF_PROVIDER_DATA_PREFIX, providerName);
4195 
4196 	/*
4197 	 * Allocate scf resources
4198 	 */
4199 	if (((pg = scf_pg_create(handle)) == NULL) ||
4200 	    ((entry1 = scf_entry_create(handle)) == NULL) ||
4201 	    ((entry2 = scf_entry_create(handle)) == NULL) ||
4202 	    ((entry3 = scf_entry_create(handle)) == NULL) ||
4203 	    ((entry5 = scf_entry_create(handle)) == NULL) ||
4204 	    ((value1 = scf_value_create(handle)) == NULL) ||
4205 	    ((value2 = scf_value_create(handle)) == NULL) ||
4206 	    ((value3 = scf_value_create(handle)) == NULL) ||
4207 	    ((value4 = scf_value_create(handle)) == NULL) ||
4208 	    ((value5 = scf_value_create(handle)) == NULL) ||
4209 	    ((prop = scf_property_create(handle)) == NULL) ||
4210 	    ((tran = scf_transaction_create(handle)) == NULL)) {
4211 		syslog(LOG_ERR, "scf alloc resource failed - %s",
4212 		    scf_strerror(scf_error()));
4213 		ret = STMF_PS_ERROR;
4214 		goto out;
4215 	}
4216 
4217 	/*
4218 	 * Get the existing property group
4219 	 */
4220 	if (scf_service_get_pg(svc, pgName, pg) == -1) {
4221 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
4222 			syslog(LOG_ERR, "get pg %s failed - %s",
4223 			    pgName, scf_strerror(scf_error()));
4224 			ret = STMF_PS_ERROR;
4225 			goto out;
4226 		} else {
4227 			/*
4228 			 * create the property group.
4229 			 */
4230 			if (scf_service_add_pg(svc, pgName,
4231 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
4232 				syslog(LOG_ERR, "add pg %s failed - %s",
4233 				    pgName, scf_strerror(scf_error()));
4234 				ret = STMF_PS_ERROR;
4235 				goto out;
4236 			}
4237 			newPg = B_TRUE;
4238 		}
4239 	}
4240 
4241 	/*
4242 	 * Begin the transaction
4243 	 */
4244 	if (scf_transaction_start(tran, pg) == -1) {
4245 		syslog(LOG_ERR, "start transaction for %s failed - %s",
4246 		    pgName, scf_strerror(scf_error()));
4247 		ret = STMF_PS_ERROR;
4248 		goto out;
4249 	}
4250 
4251 	if (!newPg) {
4252 		/*
4253 		 * Get the STMF_PROVIDER_DATA_PROP_COUNT property
4254 		 */
4255 		if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
4256 		    prop) == -1) {
4257 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4258 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4259 			    scf_strerror(scf_error()));
4260 			ret = STMF_PS_ERROR;
4261 			goto out;
4262 		}
4263 
4264 		/*
4265 		 * Get the STMF_PROVIDER_DATA_PROP_COUNT value
4266 		 */
4267 		if (scf_property_get_value(prop, value4) == -1) {
4268 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4269 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4270 			    scf_strerror(scf_error()));
4271 			ret = STMF_PS_ERROR;
4272 			goto out;
4273 		}
4274 
4275 		/*
4276 		 * Now get the actual value from the value handle
4277 		 */
4278 		if (scf_value_get_count(value4, &oldBlockCnt) == -1) {
4279 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4280 			    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4281 			    scf_strerror(scf_error()));
4282 			ret = STMF_PS_ERROR;
4283 			goto out;
4284 		}
4285 	}
4286 
4287 	/*
4288 	 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
4289 	 * If it doesn't exist, we'll create it later after successfully
4290 	 * setting the data.
4291 	 */
4292 	if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4293 	    prop) == -1) {
4294 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
4295 			foundSetCnt = B_FALSE;
4296 		} else {
4297 			syslog(LOG_ERR, "get property %s/%s failed - %s",
4298 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4299 			    scf_strerror(scf_error()));
4300 			ret = STMF_PS_ERROR;
4301 			goto out;
4302 		}
4303 	}
4304 
4305 	if (foundSetCnt) {
4306 		/*
4307 		 * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
4308 		 */
4309 		if (scf_property_get_value(prop, value5) == -1) {
4310 			syslog(LOG_ERR, "get property value %s/%s failed - %s",
4311 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4312 			    scf_strerror(scf_error()));
4313 			ret = STMF_PS_ERROR;
4314 			goto out;
4315 		}
4316 
4317 		/*
4318 		 * Now get the actual value from the value handle
4319 		 */
4320 		if (scf_value_get_count(value5, &setCnt) == -1) {
4321 			syslog(LOG_ERR, "get integer value %s/%s failed - %s",
4322 			    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4323 			    scf_strerror(scf_error()));
4324 			ret = STMF_PS_ERROR;
4325 			goto out;
4326 		}
4327 
4328 		/*
4329 		 * Compare the setCnt prop to the caller's.
4330 		 */
4331 		if (setToken && (*setToken != setCnt)) {
4332 			ret = STMF_PS_ERROR_PROV_DATA_STALE;
4333 			goto out;
4334 		}
4335 	}
4336 
4337 	setCnt++;
4338 
4339 	/*
4340 	 * prepare the list for writing
4341 	 */
4342 	if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize,
4343 	    NV_ENCODE_XDR, 0) != 0) {
4344 		syslog(LOG_ERR, "nvlist_pack for %s failed",
4345 		    pgName);
4346 		ret = STMF_PS_ERROR_NOMEM;
4347 		goto out;
4348 	}
4349 
4350 	/* Determine how many chunks we need to write */
4351 	blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE;
4352 	if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE)
4353 		blockCnt++;
4354 
4355 	/* allocate entry and value resources for writing those chunks */
4356 	addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry)
4357 	    * blockCnt);
4358 	if (addEntry == NULL) {
4359 		syslog(LOG_ERR, "addEntry alloc for %s failed", pgName);
4360 		ret = STMF_PS_ERROR_NOMEM;
4361 		goto out;
4362 	}
4363 
4364 	addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
4365 	    * blockCnt);
4366 	if (addValue == NULL) {
4367 		syslog(LOG_ERR, "value alloc for %s failed", pgName);
4368 		ret = STMF_PS_ERROR_NOMEM;
4369 		goto out;
4370 	}
4371 
4372 	/*
4373 	 * allocate entry delete resources for deleting anything existing
4374 	 * that is more than the new block count. We could leave them around
4375 	 * without suffering any ill effects but it will be cleaner to look at
4376 	 * in smf tools if they are deleted.
4377 	 */
4378 	if (oldBlockCnt > blockCnt) {
4379 		deleteEntry = (scf_transaction_entry_t **)calloc(1,
4380 		    sizeof (*deleteEntry) * (oldBlockCnt - blockCnt));
4381 		if (deleteEntry == NULL) {
4382 			syslog(LOG_ERR, "deleteEntry alloc for %s failed",
4383 			    pgName);
4384 			ret = STMF_PS_ERROR_NOMEM;
4385 			goto out;
4386 		}
4387 		deleteEntryAlloc = oldBlockCnt - blockCnt;
4388 	}
4389 
4390 
4391 	for (i = 0; i < blockCnt; i++) {
4392 		/*
4393 		 * Create the entry resource for the prop
4394 		 */
4395 		addEntry[i] = scf_entry_create(handle);
4396 		if (addEntry[i] == NULL) {
4397 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4398 			    pgName, scf_strerror(scf_error()));
4399 			ret = STMF_PS_ERROR;
4400 			goto out;
4401 		}
4402 
4403 		/* bump alloc count for addEntry allocation */
4404 		addEntryAlloc++;
4405 
4406 		/*
4407 		 * create the name to use for the property
4408 		 */
4409 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
4410 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
4411 
4412 		/*
4413 		 * Create the new property
4414 		 */
4415 		if (scf_transaction_property_new(tran, addEntry[i],
4416 		    dataPropertyName, SCF_TYPE_OPAQUE) == -1) {
4417 			if (scf_error() == SCF_ERROR_EXISTS) {
4418 				if (scf_transaction_property_change(tran,
4419 				    addEntry[i], dataPropertyName,
4420 				    SCF_TYPE_OPAQUE) == -1) {
4421 					syslog(LOG_ERR, "transaction property "
4422 					    "change %s/%s failed - %s",
4423 					    pgName, dataPropertyName,
4424 					    scf_strerror(scf_error()));
4425 					ret = STMF_PS_ERROR;
4426 					goto out;
4427 				}
4428 			} else {
4429 				syslog(LOG_ERR,
4430 				    "transaction property new %s/%s "
4431 				    "failed - %s", pgName, dataPropertyName,
4432 				    scf_strerror(scf_error()));
4433 				ret = STMF_PS_ERROR;
4434 				goto out;
4435 			}
4436 		}
4437 		/*
4438 		 * Create the value resource for the prop
4439 		 */
4440 		addValue[i] = scf_value_create(handle);
4441 		if (addValue[i] == NULL) {
4442 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4443 			    pgName, scf_strerror(scf_error()));
4444 			ret = STMF_PS_ERROR;
4445 			goto out;
4446 		}
4447 
4448 		/* bump alloc count for addValue allocation */
4449 		addValueAlloc++;
4450 
4451 		/*
4452 		 * Set the data block offset and size
4453 		 */
4454 		if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1))
4455 		    > nvlistEncodedSize) {
4456 			blockSize = nvlistEncodedSize
4457 			    - STMF_PROVIDER_DATA_PROP_SIZE * i;
4458 		} else {
4459 			blockSize = STMF_PROVIDER_DATA_PROP_SIZE;
4460 		}
4461 
4462 		blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
4463 		if (scf_value_set_opaque(addValue[i],
4464 		    &nvlistEncoded[blockOffset], blockSize) == -1) {
4465 			syslog(LOG_ERR, "set value for %s failed - %s",
4466 			    pgName, scf_strerror(scf_error()));
4467 			ret = STMF_PS_ERROR;
4468 			goto out;
4469 		}
4470 
4471 		/*
4472 		 * Add the data block to the transaction entry
4473 		 */
4474 		if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) {
4475 			syslog(LOG_ERR, "add value for %s failed - %s",
4476 			    pgName, scf_strerror(scf_error()));
4477 			ret = STMF_PS_ERROR;
4478 			goto out;
4479 		}
4480 	}
4481 
4482 	/*
4483 	 * Now we need to delete any chunks (properties) that are no longer
4484 	 * needed. Iterate through the rest of the chunks deleting each.
4485 	 */
4486 	for (i = blockCnt; i < oldBlockCnt; i++) {
4487 		/*
4488 		 * Create the entry resource for the prop
4489 		 */
4490 		deleteEntry[j] = scf_entry_create(handle);
4491 		if (deleteEntry[j] == NULL) {
4492 			syslog(LOG_ERR, "scf value alloc for %s failed - %s",
4493 			    pgName, scf_strerror(scf_error()));
4494 			ret = STMF_PS_ERROR;
4495 			goto out;
4496 		}
4497 
4498 		/*
4499 		 * create the name to use for the property
4500 		 */
4501 		(void) snprintf(dataPropertyName, sizeof (dataPropertyName),
4502 		    "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
4503 
4504 		/*
4505 		 * Delete the existing property
4506 		 */
4507 		if (scf_transaction_property_delete(tran, deleteEntry[j++],
4508 		    dataPropertyName) == -1) {
4509 			syslog(LOG_ERR, "delete property %s/%s failed - %s",
4510 			    pgName, dataPropertyName,
4511 			    scf_strerror(scf_error()));
4512 			ret = STMF_PS_ERROR;
4513 			goto out;
4514 		}
4515 	}
4516 
4517 	if (newPg) {
4518 		/*
4519 		 * Ensure the read_authorization property is set
4520 		 * for the group
4521 		 */
4522 		if (scf_transaction_property_new(tran, entry1,
4523 		    "read_authorization", SCF_TYPE_ASTRING) == -1) {
4524 			syslog(LOG_ERR, "transaction property %s/%s new "
4525 			    "failed - %s", pgName, "read_authorization",
4526 			    scf_strerror(scf_error()));
4527 			ret = STMF_PS_ERROR;
4528 			goto out;
4529 		}
4530 
4531 		if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) {
4532 			syslog(LOG_ERR, "set value %s/%s failed - %s",
4533 			    pgName, "read_authorization",
4534 			    scf_strerror(scf_error()));
4535 			ret = STMF_PS_ERROR;
4536 			goto out;
4537 		}
4538 
4539 		if (scf_entry_add_value(entry1, value1) == -1) {
4540 			syslog(LOG_ERR, "add value %s/%s failed - %s",
4541 			    pgName, "read_authorization",
4542 			    scf_strerror(scf_error()));
4543 			ret = STMF_PS_ERROR;
4544 			goto out;
4545 		}
4546 	}
4547 
4548 	/* create or change the count property */
4549 	if (scf_transaction_property_new(tran, entry2,
4550 	    STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) {
4551 		if (scf_error() == SCF_ERROR_EXISTS) {
4552 			if (scf_transaction_property_change(tran, entry2,
4553 			    STMF_PROVIDER_DATA_PROP_COUNT,
4554 			    SCF_TYPE_COUNT) == -1) {
4555 				syslog(LOG_ERR, "transaction property change "
4556 				    "%s/%s failed - %s", pgName,
4557 				    STMF_PROVIDER_DATA_PROP_COUNT,
4558 				    scf_strerror(scf_error()));
4559 				ret = STMF_PS_ERROR;
4560 				goto out;
4561 			}
4562 		} else {
4563 			syslog(LOG_ERR, "transaction property %s/%s new "
4564 			    "failed - %s", pgName,
4565 			    STMF_PROVIDER_DATA_PROP_COUNT,
4566 			    scf_strerror(scf_error()));
4567 			ret = STMF_PS_ERROR;
4568 			goto out;
4569 		}
4570 	}
4571 
4572 	scf_value_set_count(value2, blockCnt);
4573 
4574 	if (scf_entry_add_value(entry2, value2) == -1) {
4575 		syslog(LOG_ERR, "add value %s/%s failed - %s",
4576 		    pgName, STMF_PROVIDER_DATA_PROP_COUNT,
4577 		    scf_strerror(scf_error()));
4578 		ret = STMF_PS_ERROR;
4579 		goto out;
4580 	}
4581 
4582 	/* create or change the set count property */
4583 	if (scf_transaction_property_new(tran, entry5,
4584 	    STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) {
4585 		if (scf_error() == SCF_ERROR_EXISTS) {
4586 			if (scf_transaction_property_change(tran, entry5,
4587 			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4588 			    SCF_TYPE_COUNT) == -1) {
4589 				syslog(LOG_ERR,
4590 				    "transaction property change %s/%s "
4591 				    "failed - %s", pgName,
4592 				    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4593 				    scf_strerror(scf_error()));
4594 				ret = STMF_PS_ERROR;
4595 				goto out;
4596 			}
4597 		} else {
4598 			syslog(LOG_ERR, "transaction property new %s/%s "
4599 			    "failed - %s", pgName,
4600 			    STMF_PROVIDER_DATA_PROP_SET_COUNT,
4601 			    scf_strerror(scf_error()));
4602 			ret = STMF_PS_ERROR;
4603 			goto out;
4604 		}
4605 	}
4606 
4607 
4608 
4609 	scf_value_set_count(value5, setCnt);
4610 
4611 	if (scf_entry_add_value(entry5, value5) == -1) {
4612 		syslog(LOG_ERR, "add value %s/%s failed - %s",
4613 		    pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
4614 		    scf_strerror(scf_error()));
4615 		ret = STMF_PS_ERROR;
4616 		goto out;
4617 	}
4618 
4619 	/* create or change the provider type property */
4620 	if (scf_transaction_property_new(tran, entry3,
4621 	    STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) {
4622 		if (scf_error() == SCF_ERROR_EXISTS) {
4623 			if (scf_transaction_property_change(tran, entry3,
4624 			    STMF_PROVIDER_DATA_PROP_TYPE,
4625 			    SCF_TYPE_INTEGER) == -1) {
4626 				syslog(LOG_ERR,
4627 				    "transaction property change %s/%s "
4628 				    "failed - %s", pgName,
4629 				    STMF_PROVIDER_DATA_PROP_TYPE,
4630 				    scf_strerror(scf_error()));
4631 				ret = STMF_PS_ERROR;
4632 				goto out;
4633 			}
4634 		} else {
4635 			syslog(LOG_ERR, "transaction property new %s/%s "
4636 			    "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE,
4637 			    scf_strerror(scf_error()));
4638 			ret = STMF_PS_ERROR;
4639 			goto out;
4640 		}
4641 	}
4642 
4643 	switch (providerType) {
4644 		case STMF_PORT_PROVIDER_TYPE:
4645 		case STMF_LU_PROVIDER_TYPE:
4646 			scf_value_set_integer(value3, providerType);
4647 			break;
4648 		default:
4649 			ret = STMF_PS_ERROR;
4650 			goto out;
4651 	}
4652 
4653 	if (scf_entry_add_value(entry3, value3) == -1) {
4654 		syslog(LOG_ERR, "add value %s/%s failed - %s", pgName,
4655 		    STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error()));
4656 		ret = STMF_PS_ERROR;
4657 		goto out;
4658 	}
4659 
4660 
4661 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
4662 		syslog(LOG_ERR, "transaction commit for %s failed - %s",
4663 		    pgName, scf_strerror(scf_error()));
4664 		if (commitRet == 0) {
4665 			ret = STMF_PS_ERROR_BUSY;
4666 		} else {
4667 			ret = STMF_PS_ERROR;
4668 		}
4669 		goto out;
4670 	}
4671 
4672 	/* pass the new token back to the caller if requested */
4673 	if (ret == STMF_PS_SUCCESS && setToken) {
4674 		*setToken = setCnt;
4675 	}
4676 
4677 out:
4678 	/*
4679 	 * Free resources
4680 	 */
4681 	if (handle != NULL) {
4682 		scf_handle_destroy(handle);
4683 	}
4684 	if (svc != NULL) {
4685 		scf_service_destroy(svc);
4686 	}
4687 	if (pg != NULL) {
4688 		scf_pg_destroy(pg);
4689 	}
4690 	if (prop != NULL) {
4691 		scf_property_destroy(prop);
4692 	}
4693 	if (tran != NULL) {
4694 		scf_transaction_destroy(tran);
4695 	}
4696 	for (i = 0; i < addEntryAlloc; i++) {
4697 		scf_entry_destroy(addEntry[i]);
4698 	}
4699 	for (i = 0; i < addValueAlloc; i++) {
4700 		scf_value_destroy(addValue[i]);
4701 	}
4702 	free(addValue);
4703 	free(addEntry);
4704 	for (i = 0; i < deleteEntryAlloc; i++) {
4705 		scf_entry_destroy(deleteEntry[i]);
4706 	}
4707 	free(deleteEntry);
4708 	if (entry1 != NULL) {
4709 		scf_entry_destroy(entry1);
4710 	}
4711 	if (entry2 != NULL) {
4712 		scf_entry_destroy(entry2);
4713 	}
4714 	if (entry3 != NULL) {
4715 		scf_entry_destroy(entry3);
4716 	}
4717 	if (entry5 != NULL) {
4718 		scf_entry_destroy(entry5);
4719 	}
4720 	if (value1 != NULL) {
4721 		scf_value_destroy(value1);
4722 	}
4723 	if (value2 != NULL) {
4724 		scf_value_destroy(value2);
4725 	}
4726 	if (value3 != NULL) {
4727 		scf_value_destroy(value3);
4728 	}
4729 	if (value4 != NULL) {
4730 		scf_value_destroy(value4);
4731 	}
4732 	if (value5 != NULL) {
4733 		scf_value_destroy(value5);
4734 	}
4735 	if (nvlistEncoded != NULL) {
4736 		free(nvlistEncoded);
4737 	}
4738 
4739 	return (ret);
4740 }
4741 
4742 /*
4743  * psGetViewEntry
4744  *
4745  * Purpose: Get a single view entry based on the logical unit identifier and
4746  *          view entry index
4747  *
4748  * lu - logical unit identifier
4749  * viewEntryIndex - index of view entry
4750  * ve - caller allocated stmfViewEntry structure. On success, this will
4751  *      contain the retrieved view entry
4752  */
4753 int
4754 psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve)
4755 {
4756 	scf_handle_t	*handle = NULL;
4757 	scf_service_t	*svc = NULL;
4758 	scf_propertygroup_t	*pg = NULL;
4759 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
4760 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
4761 	char luPgName[LOGICAL_UNIT_PG_SIZE];
4762 	int ret = STMF_PS_SUCCESS;
4763 
4764 	ret = iPsInit(&handle, &svc);
4765 	if (ret != STMF_PS_SUCCESS) {
4766 		goto out;
4767 	}
4768 
4769 	pg = scf_pg_create(handle);
4770 	if (pg == NULL) {
4771 		syslog(LOG_ERR, "scf pg alloc failed - %s",
4772 		    scf_strerror(scf_error()));
4773 		ret = STMF_PS_ERROR;
4774 		goto out;
4775 	}
4776 
4777 	/* Convert to ASCII uppercase hexadecimal string */
4778 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
4779 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
4780 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
4781 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
4782 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
4783 	    lu->guid[14], lu->guid[15]);
4784 
4785 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
4786 	    STMF_LU_PREFIX, guidAsciiBuf);
4787 
4788 	/*
4789 	 * Format of view entry property group name:
4790 	 *	VE-<view_entry_index>-<lu_name>
4791 	 */
4792 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
4793 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
4794 
4795 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
4796 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
4797 			ret = STMF_PS_ERROR_NOT_FOUND;
4798 		} else {
4799 			syslog(LOG_ERR, "get pg %s failed - %s",
4800 			    viewEntryPgName, scf_strerror(scf_error()));
4801 			ret = STMF_PS_ERROR;
4802 		}
4803 		goto out;
4804 	}
4805 
4806 
4807 	if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) {
4808 		ret = STMF_PS_ERROR;
4809 		goto out;
4810 	}
4811 
4812 out:
4813 	/*
4814 	 * Free resources
4815 	 */
4816 	if (handle != NULL) {
4817 		scf_handle_destroy(handle);
4818 	}
4819 	if (svc != NULL) {
4820 		scf_service_destroy(svc);
4821 	}
4822 	if (pg != NULL) {
4823 		scf_pg_destroy(pg);
4824 	}
4825 
4826 	return (ret);
4827 }
4828 
4829 /*
4830  * psRemoveViewEntry
4831  *
4832  * Remove a view entry
4833  *
4834  * luGuid - identifier of logical unit from which to remove view entry
4835  * viewEntryIndex - view entry name to remove
4836  *
4837  * returns:
4838  *  STMF_PS_SUCCESS on success
4839  *  STMF_PS_ERROR_* on failure
4840  */
4841 int
4842 psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
4843 {
4844 	scf_handle_t	*handle = NULL;
4845 	scf_service_t	*svc = NULL;
4846 	scf_propertygroup_t	*pg = NULL;
4847 	char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
4848 	char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
4849 	char luPgName[LOGICAL_UNIT_PG_SIZE];
4850 	int ret = STMF_PS_SUCCESS;
4851 	sigset_t sigmaskRestore;
4852 
4853 	/* grab the signal hold lock */
4854 	(void) pthread_mutex_lock(&sigSetLock);
4855 
4856 	/*
4857 	 * hold signals until we're done
4858 	 */
4859 	if (holdSignal(&sigmaskRestore) != 0) {
4860 		(void) pthread_mutex_unlock(&sigSetLock);
4861 		return (STMF_PS_ERROR);
4862 	}
4863 
4864 	ret = iPsInit(&handle, &svc);
4865 	if (ret != STMF_PS_SUCCESS) {
4866 		goto out;
4867 	}
4868 
4869 	pg = scf_pg_create(handle);
4870 	if (pg == NULL) {
4871 		syslog(LOG_ERR, "scf pg alloc failed - %s",
4872 		    scf_strerror(scf_error()));
4873 		ret = STMF_PS_ERROR;
4874 		goto out;
4875 	}
4876 
4877 	/* Convert to ASCII uppercase hexadecimal string */
4878 	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
4879 	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
4880 	    lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
4881 	    lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
4882 	    lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
4883 	    lu->guid[14], lu->guid[15]);
4884 
4885 	(void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
4886 	    STMF_LU_PREFIX, guidAsciiBuf);
4887 
4888 	/*
4889 	 * Format of view entry property group name:
4890 	 *	VE-<view_entry_index>-<lu_name>
4891 	 */
4892 	(void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
4893 	    "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
4894 
4895 	if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
4896 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
4897 			ret = STMF_PS_ERROR_NOT_FOUND;
4898 		} else {
4899 			syslog(LOG_ERR, "get pg %s failed - %s",
4900 			    viewEntryPgName, scf_strerror(scf_error()));
4901 			ret = STMF_PS_ERROR;
4902 		}
4903 		goto out;
4904 	}
4905 
4906 	/*
4907 	 * update the logical unit property group to remove
4908 	 * the view entry and update the view entry count
4909 	 * If it fails, we won't delete the property group so that
4910 	 * we maintain consistency.
4911 	 */
4912 	if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
4913 	    REMOVE)) != STMF_PS_SUCCESS) {
4914 		goto out;
4915 	}
4916 
4917 	/*
4918 	 * Delete the view entry. If this fails, we should try to add
4919 	 * the logical unit view entry property group back otherwise
4920 	 * we're inconsistent.
4921 	 */
4922 	if (scf_pg_delete(pg) == -1) {
4923 		syslog(LOG_ERR, "delete pg %s failed - %s", viewEntryPgName,
4924 		    scf_strerror(scf_error()));
4925 		if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
4926 		    ADD)) != STMF_PS_SUCCESS) {
4927 			syslog(LOG_ERR, "add of view entry %s failed, possible"
4928 			    "inconsistency - %s", viewEntryPgName,
4929 			    scf_strerror(scf_error()));
4930 		}
4931 		ret = STMF_PS_ERROR;
4932 		goto out;
4933 	}
4934 
4935 out:
4936 	/*
4937 	 * Okay, we're done. Release the signals
4938 	 */
4939 	if (releaseSignal(&sigmaskRestore) != 0) {
4940 		/*
4941 		 * Don't set this as an STMF_PS_ERROR_*. We succeeded
4942 		 * the requested operation. But we do need to log it.
4943 		 */
4944 		syslog(LOG_ERR, "Unable to release one or more signals - %s",
4945 		    strerror(errno));
4946 	}
4947 
4948 	/*
4949 	 * Free resources
4950 	 */
4951 	if (handle != NULL) {
4952 		scf_handle_destroy(handle);
4953 	}
4954 	if (svc != NULL) {
4955 		scf_service_destroy(svc);
4956 	}
4957 	if (pg != NULL) {
4958 		scf_pg_destroy(pg);
4959 	}
4960 
4961 	/* release the signal hold lock */
4962 	(void) pthread_mutex_unlock(&sigSetLock);
4963 
4964 	return (ret);
4965 }
4966 
4967 
4968 
4969 /*
4970  * holdSignal
4971  *
4972  * Hold SIGINT, SIGTERM, SIGQUIT until further notice.
4973  *
4974  * Saves old signal mask on a per thread basis
4975  * and saves action for the process.
4976  *
4977  * Installs action for above signals.
4978  *
4979  * locks held: sigSetLock
4980  *
4981  * returns:
4982  *  0 on success
4983  *  non-zero otherwise
4984  */
4985 static int
4986 holdSignal(sigset_t *sigmaskRestore)
4987 {
4988 	struct sigaction act;
4989 	sigset_t sigmask;
4990 
4991 	/*
4992 	 * Return existing signal mask for this thread
4993 	 */
4994 	if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) {
4995 		return (1);
4996 	}
4997 
4998 	(void) sigemptyset(&act.sa_mask);
4999 	act.sa_handler = sigHandler;
5000 	act.sa_flags = 0;
5001 
5002 	/*
5003 	 * Have we set the actions for the signals we want to catch?
5004 	 */
5005 	if (!actionSet) {
5006 		if (sigaction(SIGQUIT, &act, &currentActionQuit) != 0) {
5007 			return (1);
5008 		}
5009 
5010 		if (sigaction(SIGINT, &act, &currentActionInt) != 0) {
5011 			return (1);
5012 		}
5013 
5014 		if (sigaction(SIGTERM, &act, &currentActionTerm) != 0) {
5015 			return (1);
5016 		}
5017 
5018 		actionSet = B_TRUE;
5019 	}
5020 
5021 	/*
5022 	 * We still need to change the mask for the current thread
5023 	 */
5024 	if (sigfillset(&sigmask) != 0) {
5025 		return (1);
5026 	}
5027 
5028 	(void) sigdelset(&sigmask, SIGQUIT);
5029 
5030 	(void) sigdelset(&sigmask, SIGINT);
5031 
5032 	(void) sigdelset(&sigmask, SIGTERM);
5033 
5034 	if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) {
5035 		return (1);
5036 	}
5037 
5038 	return (0);
5039 }
5040 
5041 /*
5042  * releaseSignal
5043  *
5044  * Re-install the original signal mask and signal actions
5045  *
5046  * Also, raise any signals that were caught during the hold period and clear
5047  * the signal from the caught set (signalsCaught).
5048  *
5049  * locks held: sigSetLock
5050  *
5051  * Returns
5052  *  0 on success
5053  *  non-zero otherwise
5054  */
5055 static int
5056 releaseSignal(sigset_t *sigmaskRestore)
5057 {
5058 	int ret = 0;
5059 
5060 	if (sigaction(SIGQUIT, &currentActionQuit, NULL) != 0) {
5061 		ret = 1;
5062 	}
5063 
5064 	if (sigaction(SIGINT, &currentActionInt, NULL) != 0) {
5065 		ret = 1;
5066 	}
5067 
5068 	if (sigaction(SIGTERM, &currentActionTerm, NULL) != 0) {
5069 		ret = 1;
5070 	}
5071 
5072 	actionSet = B_FALSE;
5073 
5074 	/*
5075 	 * Restore previous signal mask for this thread
5076 	 */
5077 	if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) {
5078 		syslog(LOG_ERR, "Unable to restore sigmask");
5079 	}
5080 
5081 	/*
5082 	 * Now raise signals that were raised while we were held
5083 	 */
5084 	if (sigismember(&signalsCaught, SIGTERM)) {
5085 		(void) sigdelset(&signalsCaught, SIGTERM);
5086 		(void) raise(SIGTERM);
5087 	}
5088 
5089 	if (sigismember(&signalsCaught, SIGINT)) {
5090 		(void) sigdelset(&signalsCaught, SIGINT);
5091 		(void) raise(SIGINT);
5092 	}
5093 
5094 	if (sigismember(&signalsCaught, SIGQUIT)) {
5095 		(void) sigdelset(&signalsCaught, SIGQUIT);
5096 		(void) raise(SIGQUIT);
5097 	}
5098 
5099 	return (ret);
5100 }
5101