xref: /titanic_52/usr/src/lib/libpool/common/pool.c (revision 9113a79cf228b8f7bd509b1328adf88659dfe218)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <thread.h>
34 #include <synch.h>
35 #include <unistd.h>
36 #include <stropts.h>
37 #include <fcntl.h>
38 #include <note.h>
39 #include <errno.h>
40 #include <ctype.h>
41 #include <libintl.h>
42 #include <libscf.h>
43 #include <pool.h>
44 #include <signal.h>
45 
46 #include <sys/pool.h>
47 #include <sys/priocntl.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/wait.h>
51 
52 #include "pool_internal.h"
53 #include "pool_impl.h"
54 
55 /*
56  * libpool Interface Routines
57  *
58  * pool.c implements (most of) the external interface to libpool
59  * users. Some of the interface is implemented in pool_internal.c for
60  * reasons of internal code organisation.  The core requirements for
61  * pool.c are:
62  *
63  * Data Abstraction
64  *
65  * The abstraction of the actual datastore so that no details of the
66  * underlying data representation mechanism are revealed to users of
67  * the library. For instance, the fact that we use the kernel or files
68  * to store our configurations is completely abstracted via the
69  * various libpool APIs.
70  *
71  * External Interaction
72  *
73  * libpool users manipulate configuration components via the API
74  * defined in pool.h. Most functions in this file act as interceptors,
75  * validating parameters before redirecting the request into a
76  * specific datastore implementation for the actual work to be done.
77  *
78  * These main sets of requirements have driven the design so that it
79  * is possible to replace the entire datastore type without having to
80  * modify the external (or internal provider) APIs. It is possible to
81  * modify the storage technology used by libpool by implementing a new
82  * set of datastore provider operations. Simply modify the
83  * pool_conf_open() routine to establish a new datastore as the
84  * provider for a configuration.
85  *
86  * The key components in a libpool configuration are :
87  * pool_conf_t - This represents a complete configuration instance
88  * pool_t - A pool inside a configuration
89  * pool_resource_t - A resource inside a configuration
90  * pool_component_t - A component of a resource
91  *
92  */
93 
94 /*
95  * Used to control transfer setup.
96  */
97 #define	XFER_FAIL	PO_FAIL
98 #define	XFER_SUCCESS	PO_SUCCESS
99 #define	XFER_CONTINUE	1
100 
101 #define	SMF_SVC_INSTANCE	"svc:/system/pools:default"
102 #define	E_ERROR		1		/* Exit status for error */
103 
104 #ifndef	TEXT_DOMAIN
105 #define	TEXT_DOMAIN	"SYS_TEST"
106 #endif	/* TEXT_DOMAIN */
107 
108 const char pool_info_location[] =  "/dev/pool";
109 
110 /*
111  * Static data
112  */
113 static const char static_location[] = "/etc/pooladm.conf";
114 static const char dynamic_location[] =  "/dev/poolctl";
115 static mutex_t		keylock;
116 static thread_key_t	errkey;
117 static int		keyonce = 0;
118 
119 /*
120  * libpool error code
121  */
122 static int pool_errval = POE_OK;
123 
124 /*
125  * libpool version
126  */
127 static uint_t pool_workver = POOL_VER_CURRENT;
128 
129 static const char *data_type_tags[] = {
130 	"uint",
131 	"int",
132 	"float",
133 	"boolean",
134 	"string"
135 };
136 
137 /*
138  * static functions
139  */
140 static int pool_elem_remove(pool_elem_t *);
141 static int is_valid_prop_name(const char *);
142 static int prop_buf_build_cb(pool_conf_t *, pool_elem_t *, const char *,
143     pool_value_t *, void *);
144 static char *pool_base_info(const pool_elem_t *, char_buf_t *, int);
145 static int choose_components(pool_resource_t *, pool_resource_t *, uint64_t);
146 static int pool_conf_check(const pool_conf_t *);
147 static void free_value_list(int, pool_value_t **);
148 static int setup_transfer(pool_conf_t *, pool_resource_t *, pool_resource_t *,
149     uint64_t, uint64_t *, uint64_t *);
150 
151 /*
152  * Return the "static" location string for libpool.
153  */
154 const char *
155 pool_static_location(void)
156 {
157 	return (static_location);
158 }
159 
160 /*
161  * Return the "dynamic" location string for libpool.
162  */
163 const char *
164 pool_dynamic_location(void)
165 {
166 	return (dynamic_location);
167 }
168 
169 /*
170  * Return the status for a configuration. If the configuration has
171  * been successfully opened, then the status will be POF_VALID or
172  * POF_DESTROY.  If the configuration failed to open properly or has
173  * been closed or removed, then the status will be POF_INVALID.
174  */
175 pool_conf_state_t
176 pool_conf_status(const pool_conf_t *conf)
177 {
178 	return (conf->pc_state);
179 }
180 
181 /*
182  * Bind idtype id to the pool name.
183  */
184 int
185 pool_set_binding(const char *pool_name, idtype_t idtype, id_t id)
186 {
187 	pool_conf_t *conf;
188 	int result;
189 
190 	if ((conf = pool_conf_alloc()) == NULL)
191 		return (PO_FAIL);
192 
193 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
194 		pool_conf_free(conf);
195 		pool_seterror(POE_INVALID_CONF);
196 		return (PO_FAIL);
197 	}
198 
199 	result = conf->pc_prov->pc_set_binding(conf, pool_name, idtype, id);
200 
201 	(void) pool_conf_close(conf);
202 	pool_conf_free(conf);
203 	return (result);
204 }
205 
206 /*
207  * pool_get_resource_binding() returns the binding for a pid to the supplied
208  * type of resource. If a binding cannot be determined, NULL is returned.
209  */
210 char *
211 pool_get_resource_binding(const char *sz_type, pid_t pid)
212 {
213 	pool_conf_t *conf;
214 	char *result;
215 	pool_resource_elem_class_t type;
216 
217 	if ((type = pool_resource_elem_class_from_string(sz_type)) ==
218 	    PREC_INVALID) {
219 		pool_seterror(POE_BADPARAM);
220 		return (NULL);
221 	}
222 
223 	if ((conf = pool_conf_alloc()) == NULL)
224 		return (NULL);
225 
226 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
227 	    != PO_SUCCESS) {
228 		pool_seterror(POE_INVALID_CONF);
229 		pool_conf_free(conf);
230 		return (NULL);
231 	}
232 	result = conf->pc_prov->pc_get_resource_binding(conf, type, pid);
233 	(void) pool_conf_close(conf);
234 	pool_conf_free(conf);
235 	return (result);
236 }
237 
238 /*
239  * pool_get_binding() returns the binding for a pid to a pool. If a
240  * binding cannot be determined, NULL is returned.
241  */
242 char *
243 pool_get_binding(pid_t pid)
244 {
245 	pool_conf_t *conf;
246 	char *result;
247 
248 	if ((conf = pool_conf_alloc()) == NULL)
249 		return (NULL);
250 
251 	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY)
252 	    != PO_SUCCESS) {
253 		pool_seterror(POE_INVALID_CONF);
254 		pool_conf_free(conf);
255 		return (NULL);
256 	}
257 	result = conf->pc_prov->pc_get_binding(conf, pid);
258 	(void) pool_conf_close(conf);
259 	pool_conf_free(conf);
260 	return (result);
261 }
262 
263 /*ARGSUSED*/
264 int
265 prop_buf_build_cb(pool_conf_t *UNUSED, pool_elem_t *pe, const char *name,
266     pool_value_t *pval, void *user)
267 {
268 	uint64_t u;
269 	int64_t i;
270 	uchar_t bool;
271 	const char *str;
272 	double d;
273 	char_buf_t *cb = (char_buf_t *)user;
274 	int type = pool_value_get_type(pval);
275 
276 	/*
277 	 * Ignore "type" and "<type>.name" properties as these are not
278 	 * to be displayed by this function
279 	 */
280 	if (strcmp(name, c_type) == 0 ||
281 	    strcmp(property_name_minus_ns(pe, name), c_name) == 0)
282 		return (PO_SUCCESS);
283 	if (append_char_buf(cb, "\n%s\t%s\t%s ", cb->cb_tab_buf,
284 	    data_type_tags[type], name) == PO_FAIL)
285 		return (PO_FAIL);
286 	switch (type) {
287 	case POC_UINT:
288 		(void) pool_value_get_uint64(pval, &u);
289 		if (append_char_buf(cb, "%llu", (u_longlong_t)u) == PO_FAIL)
290 			return (PO_FAIL);
291 		break;
292 	case POC_INT:
293 		(void) pool_value_get_int64(pval, &i);
294 		if (append_char_buf(cb, "%lld", (longlong_t)i) == PO_FAIL)
295 			return (PO_FAIL);
296 		break;
297 	case POC_STRING:
298 		(void) pool_value_get_string(pval, &str);
299 		if (append_char_buf(cb, "%s", str) == PO_FAIL)
300 			return (PO_FAIL);
301 		break;
302 	case POC_BOOL:
303 		(void) pool_value_get_bool(pval, &bool);
304 		if (bool == 0) {
305 			if (append_char_buf(cb, "%s", "false") == PO_FAIL)
306 				return (PO_FAIL);
307 		} else {
308 			if (append_char_buf(cb, "%s", "true") == PO_FAIL)
309 				return (PO_FAIL);
310 		}
311 		break;
312 	case POC_DOUBLE:
313 		(void) pool_value_get_double(pval, &d);
314 		if (append_char_buf(cb, "%g", d) == PO_FAIL)
315 			return (PO_FAIL);
316 		break;
317 	case POC_INVAL: /* Do nothing */
318 		break;
319 	default:
320 		return (PO_FAIL);
321 	}
322 	return (PO_SUCCESS);
323 }
324 
325 /*
326  * Return a buffer which describes the element
327  * pe is a pointer to the element
328  * deep is PO_TRUE/PO_FALSE to indicate whether children should be included
329  */
330 char *
331 pool_base_info(const pool_elem_t *pe, char_buf_t *cb, int deep)
332 {
333 	const char *sres;
334 	uint_t i;
335 	uint_t nelem;
336 
337 	pool_value_t val = POOL_VALUE_INITIALIZER;
338 	pool_resource_t **rs;
339 	pool_elem_t *elem;
340 	pool_conf_t *conf = TO_CONF(pe);
341 
342 	if (cb == NULL) {
343 		char *ret = NULL;
344 
345 		if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
346 			return (NULL);
347 
348 		/*
349 		 * Populate the buffer with element details
350 		 */
351 		(void) pool_base_info(pe, cb, deep);
352 		if (cb->cb_buf)
353 			ret = strdup(cb->cb_buf);
354 		free_char_buf(cb);
355 		return (ret);
356 	}
357 
358 	if (append_char_buf(cb, "\n%s%s", cb->cb_tab_buf,
359 		pool_elem_class_string(pe)) == PO_FAIL) {
360 		return (NULL);
361 	}
362 
363 	if (pool_get_ns_property(pe, c_name, &val) == POC_STRING) {
364 		(void) pool_value_get_string(&val, &sres);
365 		if (append_char_buf(cb, " %s", sres) == PO_FAIL) {
366 			return (NULL);
367 		}
368 	}
369 
370 	/*
371 	 * Add in some details about the element
372 	 */
373 	if (pool_walk_properties(conf, (pool_elem_t *)pe, cb,
374 	    prop_buf_build_cb) == PO_FAIL) {
375 		(void) append_char_buf(cb, "\n%s%s\n", cb->cb_tab_buf,
376 		    "Cannot access the properties of this element.");
377 		return (NULL);
378 	}
379 	if (append_char_buf(cb, "%s", "\n") == PO_FAIL)
380 		return (NULL);
381 
382 	if (pe->pe_class == PEC_POOL) {
383 		/*
384 		 * A shallow display of a pool only lists the resources by name
385 		 */
386 
387 		if ((rs = pool_query_pool_resources(conf, pool_elem_pool(pe),
388 		    &nelem, NULL)) == NULL) {
389 			return (NULL);
390 		}
391 
392 		for (i = 0; i < nelem; i++) {
393 			const char *str;
394 
395 			elem = TO_ELEM(rs[i]);
396 
397 			if (append_char_buf(cb, "\t%s%s", cb->cb_tab_buf,
398 			    pool_elem_class_string(elem)) == PO_FAIL) {
399 				free(rs);
400 				return (NULL);
401 			}
402 
403 			if (pool_get_ns_property(elem, c_name, &val) !=
404 			    POC_STRING) {
405 				free(rs);
406 				pool_seterror(POE_INVALID_CONF);
407 				return (NULL);
408 			}
409 			(void) pool_value_get_string(&val, &str);
410 			if (append_char_buf(cb, "\t%s\n", str) == PO_FAIL) {
411 				free(rs);
412 				return (NULL);
413 			}
414 		}
415 		free(rs);
416 	}
417 	if (deep == PO_TRUE) {
418 		pool_t **ps;
419 		pool_component_t **cs;
420 
421 		if (strlcat(cb->cb_tab_buf, "\t", CB_TAB_BUF_SIZE)
422 		    >= CB_TAB_BUF_SIZE) {
423 			pool_seterror(POE_SYSTEM);
424 			return (NULL);
425 		}
426 		switch (pe->pe_class) {
427 		case PEC_SYSTEM:
428 			if ((ps = pool_query_pools(conf, &nelem, NULL)) !=
429 			    NULL) { /* process the pools */
430 				for (i = 0; i < nelem; i++) {
431 					elem = TO_ELEM(ps[i]);
432 					if (pool_base_info(elem, cb,
433 					    PO_FALSE) == NULL) {
434 						free(ps);
435 						return (NULL);
436 					}
437 				}
438 				free(ps);
439 			}
440 			if ((rs = pool_query_resources(conf, &nelem, NULL)) !=
441 			    NULL) {
442 				for (i = 0; i < nelem; i++) {
443 					elem = TO_ELEM(rs[i]);
444 					if (pool_base_info(elem, cb,
445 					    PO_TRUE) == NULL) {
446 						free(rs);
447 						return (NULL);
448 					}
449 				}
450 				free(rs);
451 			}
452 			break;
453 		case PEC_POOL:
454 			if ((rs = pool_query_pool_resources(conf,
455 			    pool_elem_pool(pe), &nelem, NULL)) == NULL)
456 				return (NULL);
457 			for (i = 0; i < nelem; i++) {
458 				elem = TO_ELEM(rs[i]);
459 				if (pool_base_info(elem, cb, PO_TRUE) == NULL) {
460 					free(rs);
461 					return (NULL);
462 				}
463 			}
464 			free(rs);
465 			break;
466 		case PEC_RES_COMP:
467 			if ((cs = pool_query_resource_components(conf,
468 			    pool_elem_res(pe), &nelem, NULL)) != NULL) {
469 				for (i = 0; i < nelem; i++) {
470 					elem = TO_ELEM(cs[i]);
471 					if (pool_base_info(elem, cb,
472 					    PO_FALSE) == NULL) {
473 						free(cs);
474 						return (NULL);
475 					}
476 				}
477 				free(cs);
478 			}
479 			break;
480 		case PEC_RES_AGG:
481 		case PEC_COMP:
482 			break;
483 		default:
484 			/*NOTREACHED*/
485 			break;
486 		}
487 		if (cb->cb_tab_buf[0] != 0)
488 			cb->cb_tab_buf[strlen(cb->cb_tab_buf) - 1] = 0;
489 	}
490 	return (cb->cb_buf);
491 }
492 
493 /*
494  * Returns	The information on the specified pool or NULL.
495  *
496  * Errors	If the status of the conf is INVALID or the supplied
497  *		value of deep is illegal, POE_BADPARAM.
498  *
499  * The caller is responsible for free(3c)ing the string returned.
500  */
501 char *
502 pool_info(const pool_conf_t *conf, const pool_t *pool, int deep)
503 {
504 	pool_elem_t *pe;
505 
506 	pe = TO_ELEM(pool);
507 
508 	if (TO_CONF(pe) != conf) {
509 		pool_seterror(POE_BADPARAM);
510 		return (NULL);
511 	}
512 
513 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
514 		pool_seterror(POE_BADPARAM);
515 		return (NULL);
516 	}
517 
518 	return (pool_base_info(pe, NULL, deep));
519 }
520 
521 /*
522  * Returns	The information on the specified resource or NULL.
523  *
524  * Errors	If the status of the conf is INVALID or the supplied
525  *		value of deep is illegal, POE_BADPARAM.
526  *
527  * The caller is responsible for free(3c)ing the string returned.
528  */
529 char *
530 pool_resource_info(const pool_conf_t *conf, const pool_resource_t *res,
531     int deep)
532 {
533 	pool_elem_t *pe;
534 
535 	pe = TO_ELEM(res);
536 
537 	if (TO_CONF(pe) != conf) {
538 		pool_seterror(POE_BADPARAM);
539 		return (NULL);
540 	}
541 
542 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
543 		pool_seterror(POE_BADPARAM);
544 		return (NULL);
545 	}
546 
547 	return (pool_base_info(pe, NULL, deep));
548 }
549 
550 /*
551  * Returns	The information on the specified component or NULL.
552  *
553  * Errors	If the status of the conf is INVALID or the supplied
554  *		value of deep is illegal, POE_BADPARAM.
555  *
556  * The caller is responsible for free(3c)ing the string returned.
557  */
558 char *
559 pool_component_info(const pool_conf_t *conf, const pool_component_t *comp,
560     int deep)
561 {
562 	pool_elem_t *pe;
563 
564 	pe = TO_ELEM(comp);
565 
566 	if (TO_CONF(pe) != conf) {
567 		pool_seterror(POE_BADPARAM);
568 		return (NULL);
569 	}
570 
571 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
572 		pool_seterror(POE_BADPARAM);
573 		return (NULL);
574 	}
575 
576 	return (pool_base_info(pe, NULL, deep));
577 }
578 
579 /*
580  * Returns	The information on the specified conf or NULL.
581  *
582  * Errors	If the status of the conf is INVALID or the supplied
583  *		value of deep is illegal, POE_BADPARAM.
584  *
585  * The caller is responsible for free(3c)ing the string returned.
586  */
587 char *
588 pool_conf_info(const pool_conf_t *conf, int deep)
589 {
590 	pool_elem_t *pe;
591 
592 	if (pool_conf_status(conf) == POF_INVALID || (deep & ~1)) {
593 		pool_seterror(POE_BADPARAM);
594 		return (NULL);
595 	}
596 	if ((pe = pool_conf_to_elem(conf)) == NULL) {
597 		pool_seterror(POE_BADPARAM);
598 		return (NULL);
599 	}
600 	return (pool_base_info(pe, NULL, deep));
601 }
602 
603 
604 /*
605  * Set the thread specific error value.
606  */
607 void
608 pool_seterror(int errval)
609 {
610 	if (thr_main()) {
611 		pool_errval = errval;
612 		return;
613 	}
614 	if (keyonce == 0) {
615 		(void) mutex_lock(&keylock);
616 		if (keyonce == 0) {
617 			(void) thr_keycreate(&errkey, 0);
618 			keyonce++;
619 		}
620 		(void) mutex_unlock(&keylock);
621 	}
622 	(void) thr_setspecific(errkey, (void *)(intptr_t)errval);
623 }
624 
625 /*
626  * Return the current value of the error code.
627  * Returns: int error code
628  */
629 int
630 pool_error(void)
631 {
632 	void *errval;
633 
634 	if (thr_main())
635 		return (pool_errval);
636 	if (keyonce == 0)
637 		return (POE_OK);
638 	(void) thr_getspecific(errkey, &errval);
639 	return ((intptr_t)errval);
640 }
641 
642 /*
643  * Return the text represenation for the current value of the error code.
644  * Returns: const char * error string
645  */
646 const char *
647 pool_strerror(int error)
648 {
649 	char *str;
650 
651 	switch (error) {
652 	case POE_OK:
653 		str = dgettext(TEXT_DOMAIN, "Operation successful");
654 		break;
655 	case POE_BAD_PROP_TYPE:
656 		str = dgettext(TEXT_DOMAIN,
657 		    "Attempted to retrieve the wrong property type");
658 		break;
659 	case POE_INVALID_CONF:
660 		str = dgettext(TEXT_DOMAIN, "Invalid configuration");
661 		break;
662 	case POE_NOTSUP:
663 		str = dgettext(TEXT_DOMAIN, "Operation is not supported");
664 		break;
665 	case POE_INVALID_SEARCH:
666 		str = dgettext(TEXT_DOMAIN, "Invalid search");
667 		break;
668 	case POE_BADPARAM:
669 		str = dgettext(TEXT_DOMAIN, "Bad parameter supplied");
670 		break;
671 	case POE_PUTPROP:
672 		str = dgettext(TEXT_DOMAIN, "Error putting property");
673 		break;
674 	case POE_DATASTORE:
675 		str = dgettext(TEXT_DOMAIN, "Pools repository error");
676 		break;
677 	case POE_SYSTEM:
678 		str = dgettext(TEXT_DOMAIN, "System error");
679 		break;
680 	case POE_ACCESS:
681 		str = dgettext(TEXT_DOMAIN, "Permission denied");
682 		break;
683 	default:
684 		errno = ESRCH;
685 		str = NULL;
686 	}
687 	return (str);
688 }
689 
690 int
691 pool_get_status(int *state)
692 {
693 	int fd;
694 	pool_status_t status;
695 
696 	if ((fd = open(pool_info_location, O_RDONLY)) < 0) {
697 		pool_seterror(POE_SYSTEM);
698 		return (PO_FAIL);
699 	}
700 	if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
701 		(void) close(fd);
702 		pool_seterror(POE_SYSTEM);
703 		return (PO_FAIL);
704 	}
705 	(void) close(fd);
706 
707 	*state = status.ps_io_state;
708 
709 	return (PO_SUCCESS);
710 }
711 
712 int
713 pool_set_status(int state)
714 {
715 	int old_state;
716 
717 	if (pool_get_status(&old_state) != PO_SUCCESS) {
718 		pool_seterror(POE_SYSTEM);
719 		return (PO_FAIL);
720 	}
721 
722 	if (old_state != state) {
723 		int fd;
724 		pool_status_t status;
725 		char *fmri;
726 
727 		/*
728 		 * Changing the status of pools is performed by enabling
729 		 * or disabling the pools service instance. If this
730 		 * function has not been invoked by startd then we simply
731 		 * enable/disable the service and return success.
732 		 *
733 		 * There is no way to specify that state changes must be
734 		 * synchronous using the library API as yet, so we use
735 		 * the -s option provided by svcadm.
736 		 */
737 		fmri = getenv("SMF_FMRI");
738 		if (fmri == NULL) {
739 			FILE *p;
740 			char *cmd;
741 
742 			if (state != 0) {
743 				cmd = "/usr/sbin/svcadm enable -s " \
744 				    SMF_SVC_INSTANCE;
745 			} else {
746 				cmd = "/usr/sbin/svcadm disable -s " \
747 				    SMF_SVC_INSTANCE;
748 			}
749 			if ((p = popen(cmd, "wF")) == NULL || pclose(p) != 0) {
750 				pool_seterror(POE_SYSTEM);
751 				return (PO_FAIL);
752 			}
753 			return (PO_SUCCESS);
754 		}
755 
756 		if ((fd = open(pool_dynamic_location(), O_RDWR | O_EXCL)) < 0) {
757 			pool_seterror(POE_SYSTEM);
758 			return (PO_FAIL);
759 		}
760 
761 		/*
762 		 * If pools are being enabled/disabled by another smf service,
763 		 * enable the smf service instance.  This must be done
764 		 * asynchronously as one service cannot synchronously
765 		 * enable/disable another.
766 		 */
767 		if (strcmp(fmri, SMF_SVC_INSTANCE) != 0) {
768 			int res;
769 
770 			if (state != 0)
771 				res = smf_enable_instance(SMF_SVC_INSTANCE, 0);
772 			else
773 				res = smf_disable_instance(SMF_SVC_INSTANCE, 0);
774 
775 			if (res != 0) {
776 				(void) close(fd);
777 				pool_seterror(POE_SYSTEM);
778 				return (PO_FAIL);
779 			}
780 		}
781 		status.ps_io_state = state;
782 
783 		if (ioctl(fd, POOL_STATUS, &status) < 0) {
784 			(void) close(fd);
785 			pool_seterror(POE_SYSTEM);
786 			return (PO_FAIL);
787 		}
788 
789 		(void) close(fd);
790 
791 	}
792 	return (PO_SUCCESS);
793 }
794 
795 /*
796  * General Data Provider Independent Access Methods
797  */
798 
799 /*
800  * Property manipulation code.
801  *
802  * The pool_(get|rm|set)_property() functions consult the plugins before
803  * looking at the actual configuration. This allows plugins to provide
804  * "virtual" properties that may not exist in the configuration file per se,
805  * but behave like regular properties. This also allows plugins to reserve
806  * certain properties as read-only, non-removable, etc.
807  *
808  * A negative value returned from the plugin denotes error, 0 means that the
809  * property request should be forwarded to the backend, and 1 means the request
810  * was satisfied by the plugin and should not be processed further.
811  *
812  * The (get|rm|set)_property() functions bypass the plugin layer completely,
813  * and hence should not be generally used.
814  */
815 
816 /*
817  * Return true if the string passed in matches the pattern
818  * [A-Za-z][A-Za-z0-9,._-]*
819  */
820 int
821 is_valid_name(const char *name)
822 {
823 	int i;
824 	char c;
825 
826 	if (name == NULL)
827 		return (PO_FALSE);
828 	if (!isalpha(name[0]))
829 		return (PO_FALSE);
830 	for (i = 1; (c = name[i]) != '\0'; i++) {
831 		if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
832 			return (PO_FALSE);
833 	}
834 	return (PO_TRUE);
835 }
836 
837 /*
838  * Return true if the string passed in matches the pattern
839  * [A-Za-z_][A-Za-z0-9,._-]*
840  * A property name starting with a '_' is an "invisible" property that does not
841  * show up in a property walk.
842  */
843 int
844 is_valid_prop_name(const char *prop_name)
845 {
846 	int i;
847 	char c;
848 
849 	if (prop_name == NULL)
850 		return (PO_FALSE);
851 	if (!isalpha(prop_name[0]) && prop_name[0] != '_')
852 		return (PO_FALSE);
853 	for (i = 1; (c = prop_name[i]) != '\0'; i++) {
854 		if (!isalnum(c) && c != ',' && c != '.' && c != '_' && c != '-')
855 			return (PO_FALSE);
856 	}
857 	return (PO_TRUE);
858 }
859 
860 /*
861  * Return the specified property value.
862  *
863  * POC_INVAL is returned if an error is detected and the error code is updated
864  * to indicate the cause of the error.
865  */
866 pool_value_class_t
867 pool_get_property(const pool_conf_t *conf, const pool_elem_t *pe,
868     const char *name, pool_value_t *val)
869 {
870 	const pool_prop_t *prop_info;
871 
872 	if (pool_conf_status(conf) == POF_INVALID) {
873 		pool_seterror(POE_BADPARAM);
874 		return (POC_INVAL);
875 	}
876 	if (pool_value_set_name(val, name) != PO_SUCCESS) {
877 		return (POC_INVAL);
878 	}
879 	/*
880 	 * Check to see if this is a property we are managing. If it
881 	 * is and it has an interceptor installed for property
882 	 * retrieval, use it.
883 	 */
884 	if ((prop_info = provider_get_prop(pe, name)) != NULL &&
885 	    prop_info->pp_op.ppo_get_value != NULL) {
886 		if (prop_info->pp_op.ppo_get_value(pe, val) == PO_FAIL)
887 			return (POC_INVAL);
888 		else
889 			return (pool_value_get_type(val));
890 	}
891 	return (pe->pe_get_prop(pe, name, val));
892 }
893 
894 /*
895  * Return the specified property value with the namespace prepended.
896  * e.g. If this function is used to get the property "name" on a pool, it will
897  * attempt to retrieve "pool.name".
898  *
899  * POC_INVAL is returned if an error is detected and the error code is updated
900  * to indicate the cause of the error.
901  */
902 pool_value_class_t
903 pool_get_ns_property(const pool_elem_t *pe, const char *name, pool_value_t *val)
904 {
905 	int ret;
906 	char_buf_t *cb;
907 
908 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
909 		return (POC_INVAL);
910 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
911 	    PO_FAIL) {
912 		free_char_buf(cb);
913 		return (POC_INVAL);
914 	}
915 	ret = pool_get_property(TO_CONF(pe), pe, cb->cb_buf, val);
916 	free_char_buf(cb);
917 	return (ret);
918 }
919 
920 /*
921  * Update the specified property value.
922  *
923  * PO_FAIL is returned if an error is detected and the error code is updated
924  * to indicate the cause of the error.
925  */
926 int
927 pool_put_property(pool_conf_t *conf, pool_elem_t *pe, const char *name,
928     const pool_value_t *val)
929 {
930 	const pool_prop_t *prop_info;
931 
932 	if (pool_conf_check(conf) != PO_SUCCESS)
933 		return (PO_FAIL);
934 
935 	if (TO_CONF(pe) != conf) {
936 		pool_seterror(POE_BADPARAM);
937 		return (NULL);
938 	}
939 
940 	/* Don't allow (re)setting of the "temporary" property */
941 	if (!is_valid_prop_name(name) || strstr(name, ".temporary") != NULL) {
942 		pool_seterror(POE_BADPARAM);
943 		return (PO_FAIL);
944 	}
945 
946 	/* Don't allow rename of temporary pools/resources */
947 	if (strstr(name, ".name") != NULL && elem_is_tmp(pe)) {
948 		boolean_t rename = B_TRUE;
949 		pool_value_t *pv = pool_value_alloc();
950 
951 		if (pe->pe_get_prop(pe, name, pv) != POC_INVAL) {
952 			const char *s1 = NULL;
953 			const char *s2 = NULL;
954 
955 			(void) pool_value_get_string(pv, &s1);
956 			(void) pool_value_get_string(val, &s2);
957 			if (s1 != NULL && s2 != NULL && strcmp(s1, s2) == 0)
958 				rename = B_FALSE;
959 		}
960 		pool_value_free(pv);
961 
962 		if (rename) {
963 			pool_seterror(POE_BADPARAM);
964 			return (PO_FAIL);
965 		}
966 	}
967 
968 	/*
969 	 * Check to see if this is a property we are managing. If it is,
970 	 * ensure that we are happy with what the user is doing.
971 	 */
972 	if ((prop_info = provider_get_prop(pe, name)) != NULL) {
973 		if (prop_is_readonly(prop_info) == PO_TRUE) {
974 			pool_seterror(POE_BADPARAM);
975 			return (PO_FAIL);
976 		}
977 		if (prop_info->pp_op.ppo_set_value &&
978 		    prop_info->pp_op.ppo_set_value(pe, val) == PO_FAIL)
979 			return (PO_FAIL);
980 	}
981 
982 	return (pe->pe_put_prop(pe, name, val));
983 }
984 
985 /*
986  * Set temporary property to flag as a temporary element.
987  *
988  * PO_FAIL is returned if an error is detected and the error code is updated
989  * to indicate the cause of the error.
990  */
991 int
992 pool_set_temporary(pool_conf_t *conf, pool_elem_t *pe)
993 {
994 	int res;
995 	char name[128];
996 	pool_value_t *val;
997 
998 	if (pool_conf_check(conf) != PO_SUCCESS)
999 		return (PO_FAIL);
1000 
1001 	if (TO_CONF(pe) != conf) {
1002 		pool_seterror(POE_BADPARAM);
1003 		return (PO_FAIL);
1004 	}
1005 
1006 	/* create property name based on element type */
1007 	if (snprintf(name, sizeof (name), "%s.temporary",
1008 	    pool_elem_class_string(pe)) > sizeof (name)) {
1009 		pool_seterror(POE_SYSTEM);
1010 		return (PO_FAIL);
1011 	}
1012 
1013 	if ((val = pool_value_alloc()) == NULL)
1014 		return (PO_FAIL);
1015 
1016 	pool_value_set_bool(val, (uchar_t)1);
1017 
1018 	res = pe->pe_put_prop(pe, name, val);
1019 
1020 	pool_value_free(val);
1021 
1022 	return (res);
1023 }
1024 
1025 /*
1026  * Update the specified property value with the namespace prepended.
1027  * e.g. If this function is used to update the property "name" on a pool, it
1028  * will attempt to update "pool.name".
1029  *
1030  * PO_FAIL is returned if an error is detected and the error code is updated
1031  * to indicate the cause of the error.
1032  */
1033 int
1034 pool_put_ns_property(pool_elem_t *pe, const char *name,
1035     const pool_value_t *val)
1036 {
1037 	char_buf_t *cb;
1038 	int ret;
1039 
1040 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1041 		return (PO_FAIL);
1042 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1043 	    PO_FAIL) {
1044 		free_char_buf(cb);
1045 		return (PO_FAIL);
1046 	}
1047 	ret = pool_put_property(TO_CONF(pe), pe, cb->cb_buf, val);
1048 	free_char_buf(cb);
1049 	return (ret);
1050 }
1051 
1052 /*
1053  * Update the specified property value. Do not use the property
1054  * protection mechanism. This function should only be used for cases
1055  * where the library must bypass the normal property protection
1056  * mechanism. The only known use is to update properties in the static
1057  * configuration when performing a commit.
1058  *
1059  * PO_FAIL is returned if an error is detected and the error code is
1060  * updated to indicate the cause of the error.
1061  */
1062 int
1063 pool_put_any_property(pool_elem_t *pe, const char *name,
1064     const pool_value_t *val)
1065 {
1066 	if (!is_valid_prop_name(name)) {
1067 		pool_seterror(POE_BADPARAM);
1068 		return (PO_FAIL);
1069 	}
1070 
1071 	return (pe->pe_put_prop(pe, name, val));
1072 }
1073 
1074 /*
1075  * Update the specified property value with the namespace prepended.
1076  * e.g. If this function is used to update the property "name" on a pool, it
1077  * will attempt to update "pool.name".
1078  *
1079  * PO_FAIL is returned if an error is detected and the error code is updated
1080  * to indicate the cause of the error.
1081  */
1082 int
1083 pool_put_any_ns_property(pool_elem_t *pe, const char *name,
1084     const pool_value_t *val)
1085 {
1086 	char_buf_t *cb;
1087 	int ret;
1088 
1089 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
1090 		return (PO_FAIL);
1091 	if (set_char_buf(cb, "%s.%s", pool_elem_class_string(pe), name) ==
1092 	    PO_FAIL) {
1093 		free_char_buf(cb);
1094 		return (PO_FAIL);
1095 	}
1096 	ret = pool_put_any_property(pe, cb->cb_buf, val);
1097 	free_char_buf(cb);
1098 	return (ret);
1099 }
1100 
1101 /*
1102  * Remove the specified property value. Note that some properties are
1103  * mandatory and thus failure to remove these properties is inevitable.
1104  * PO_FAIL is returned if an error is detected and the error code is updated
1105  * to indicate the cause of the error.
1106  */
1107 int
1108 pool_rm_property(pool_conf_t *conf, pool_elem_t *pe, const char *name)
1109 {
1110 	const pool_prop_t *prop_info;
1111 
1112 	if (pool_conf_check(conf) != PO_SUCCESS)
1113 		return (PO_FAIL);
1114 
1115 	if (TO_CONF(pe) != conf) {
1116 		pool_seterror(POE_BADPARAM);
1117 		return (NULL);
1118 	}
1119 
1120 	/* Don't allow removal of the "temporary" property */
1121 	if (strstr(name, ".temporary") != NULL) {
1122 		pool_seterror(POE_BADPARAM);
1123 		return (PO_FAIL);
1124 	}
1125 
1126 	/*
1127 	 * Check to see if this is a property we are managing. If it is,
1128 	 * ensure that we are happy with what the user is doing.
1129 	 */
1130 	if ((prop_info = provider_get_prop(pe, name)) != NULL) {
1131 		if (prop_is_optional(prop_info) == PO_FALSE) {
1132 			pool_seterror(POE_BADPARAM);
1133 			return (PO_FAIL);
1134 		}
1135 	}
1136 	return (pe->pe_rm_prop(pe, name));
1137 }
1138 
1139 /*
1140  * Check if the supplied name is a namespace protected property for the supplied
1141  * element, pe. If it is, return the prefix, otherwise just return NULL.
1142  */
1143 const char *
1144 is_ns_property(const pool_elem_t *pe, const char *name)
1145 {
1146 	const char *prefix;
1147 
1148 	if ((prefix = pool_elem_class_string(pe)) != NULL) {
1149 		if (strncmp(name, prefix, strlen(prefix)) == 0)
1150 			return (prefix);
1151 	}
1152 	return (NULL);
1153 }
1154 
1155 /*
1156  * Check if the supplied name is a namespace protected property for the supplied
1157  * element, pe. If it is, return the property name with the namespace stripped,
1158  * otherwise just return the name.
1159  */
1160 const char *
1161 property_name_minus_ns(const pool_elem_t *pe, const char *name)
1162 {
1163 	const char *prefix;
1164 	if ((prefix = is_ns_property(pe, name)) != NULL) {
1165 		return (name + strlen(prefix) + 1);
1166 	}
1167 	return (name);
1168 }
1169 
1170 /*
1171  * Create an element to represent a pool and add it to the supplied
1172  * configuration.
1173  */
1174 pool_t *
1175 pool_create(pool_conf_t *conf, const char *name)
1176 {
1177 	pool_elem_t *pe;
1178 	pool_value_t val = POOL_VALUE_INITIALIZER;
1179 	const pool_prop_t *default_props;
1180 
1181 	if (pool_conf_check(conf) != PO_SUCCESS)
1182 		return (NULL);
1183 
1184 	if (!is_valid_name(name) || pool_get_pool(conf, name) != NULL) {
1185 		/*
1186 		 * A pool with the same name exists. Reject.
1187 		 */
1188 		pool_seterror(POE_BADPARAM);
1189 		return (NULL);
1190 	}
1191 	if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_POOL, PREC_INVALID,
1192 	    PCEC_INVALID)) == NULL) {
1193 		pool_seterror(POE_INVALID_CONF);
1194 		return (NULL);
1195 	}
1196 	if ((default_props = provider_get_props(pe)) != NULL) {
1197 		int i;
1198 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1199 			if (prop_is_init(&default_props[i]) &&
1200 			    (pool_put_any_property(pe,
1201 			    default_props[i].pp_pname,
1202 			    &default_props[i].pp_value) == PO_FAIL)) {
1203 				(void) pool_destroy(conf, pool_elem_pool(pe));
1204 				return (NULL);
1205 			}
1206 		}
1207 	}
1208 	if (pool_value_set_string(&val, name) != PO_SUCCESS) {
1209 		(void) pool_destroy(conf, pool_elem_pool(pe));
1210 		pool_seterror(POE_SYSTEM);
1211 		return (NULL);
1212 	}
1213 	if (pool_put_property(conf, pe, "pool.name", &val) == PO_FAIL) {
1214 		(void) pool_destroy(conf, pool_elem_pool(pe));
1215 		pool_seterror(POE_PUTPROP);
1216 		return (NULL);
1217 	}
1218 
1219 	/*
1220 	 * If we are creating a temporary pool configuration, flag the pool.
1221 	 */
1222 	if (conf->pc_prov->pc_oflags & PO_TEMP) {
1223 		if (pool_set_temporary(conf, pe) == PO_FAIL) {
1224 			(void) pool_destroy(conf, pool_elem_pool(pe));
1225 			return (NULL);
1226 		}
1227 	}
1228 
1229 	return (pool_elem_pool(pe));
1230 }
1231 
1232 /*
1233  * Create an element to represent a res.
1234  */
1235 pool_resource_t *
1236 pool_resource_create(pool_conf_t *conf, const char *sz_type, const char *name)
1237 {
1238 	pool_elem_t *pe;
1239 	pool_value_t val = POOL_VALUE_INITIALIZER;
1240 	const pool_prop_t *default_props;
1241 	pool_resource_t **resources;
1242 	int is_default = 0;
1243 	uint_t nelem;
1244 	pool_elem_class_t elem_class;
1245 	pool_resource_elem_class_t type;
1246 	pool_value_t *props[] = { NULL, NULL };
1247 
1248 	if (pool_conf_check(conf) != PO_SUCCESS)
1249 		return (NULL);
1250 
1251 	if ((type = pool_resource_elem_class_from_string(sz_type)) ==
1252 	    PREC_INVALID) {
1253 		pool_seterror(POE_BADPARAM);
1254 		return (NULL);
1255 	}
1256 
1257 	if (strcmp(sz_type, "pset") != 0) {
1258 		pool_seterror(POE_BADPARAM);
1259 		return (NULL);
1260 	}
1261 
1262 	if (!is_valid_name(name) || pool_get_resource(conf, sz_type, name) !=
1263 	    NULL) {
1264 		/*
1265 		 * Resources must be unique by name+type.
1266 		 */
1267 		pool_seterror(POE_BADPARAM);
1268 		return (NULL);
1269 	}
1270 
1271 	props[0] = &val;
1272 
1273 	if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1274 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
1275 		return (NULL);
1276 	}
1277 
1278 	if ((resources = pool_query_resources(conf, &nelem, props)) == NULL) {
1279 		/*
1280 		 * This is the first representative of this type; when it's
1281 		 * created it should be created with 'default' = 'true'.
1282 		 */
1283 		is_default = 1;
1284 	} else {
1285 		free(resources);
1286 	}
1287 	/*
1288 	 * TODO: If Additional PEC_RES_COMP types are added to
1289 	 * pool_impl.h, this would need to be extended.
1290 	 */
1291 	switch (type) {
1292 	case PREC_PSET:
1293 		elem_class = PEC_RES_COMP;
1294 		break;
1295 	default:
1296 		elem_class = PEC_RES_AGG;
1297 		break;
1298 	}
1299 	if ((pe = conf->pc_prov->pc_elem_create(conf, elem_class, type,
1300 	    PCEC_INVALID)) == NULL) {
1301 		pool_seterror(POE_INVALID_CONF);
1302 		return (NULL);
1303 	}
1304 
1305 	/*
1306 	 * The plugins contain a list of default properties and their values
1307 	 * for resources. The resource returned, hence, is fully initialized.
1308 	 */
1309 	if ((default_props = provider_get_props(pe)) != NULL) {
1310 		int i;
1311 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1312 			if (prop_is_init(&default_props[i]) &&
1313 			    pool_put_any_property(pe, default_props[i].pp_pname,
1314 			    &default_props[i].pp_value) == PO_FAIL) {
1315 				(void) pool_resource_destroy(conf,
1316 				    pool_elem_res(pe));
1317 				return (NULL);
1318 			}
1319 		}
1320 	}
1321 	if (pool_value_set_string(&val, name) != PO_SUCCESS ||
1322 	    pool_put_ns_property(pe, "name", &val) != PO_SUCCESS) {
1323 		(void) pool_resource_destroy(conf, pool_elem_res(pe));
1324 		return (NULL);
1325 	}
1326 	if (is_default) {
1327 		pool_value_set_bool(&val, PO_TRUE);
1328 		if (pool_put_any_ns_property(pe, "default", &val) !=
1329 		    PO_SUCCESS) {
1330 			(void) pool_resource_destroy(conf, pool_elem_res(pe));
1331 			return (NULL);
1332 		}
1333 	}
1334 
1335 	/*
1336 	 * If we are creating a temporary pool configuration, flag the resource.
1337 	 */
1338 	if (conf->pc_prov->pc_oflags & PO_TEMP) {
1339 		if (pool_set_temporary(conf, pe) != PO_SUCCESS) {
1340 			(void) pool_resource_destroy(conf, pool_elem_res(pe));
1341 			return (NULL);
1342 		}
1343 	}
1344 
1345 	return (pool_elem_res(pe));
1346 }
1347 
1348 /*
1349  * Create an element to represent a resource component.
1350  */
1351 pool_component_t *
1352 pool_component_create(pool_conf_t *conf, const pool_resource_t *res,
1353     int64_t sys_id)
1354 {
1355 	pool_elem_t *pe;
1356 	pool_value_t val = POOL_VALUE_INITIALIZER;
1357 	const pool_prop_t *default_props;
1358 	char refbuf[KEY_BUFFER_SIZE];
1359 
1360 	if ((pe = conf->pc_prov->pc_elem_create(conf, PEC_COMP,
1361 	    PREC_INVALID, PCEC_CPU)) == NULL) {
1362 		pool_seterror(POE_INVALID_CONF);
1363 		return (NULL);
1364 	}
1365 	/*
1366 	 * TODO: If additional PEC_COMP types are added in pool_impl.h,
1367 	 * this would need to be extended.
1368 	 */
1369 	pe->pe_component_class = PCEC_CPU;
1370 	/* Now set the container for this comp */
1371 	if (pool_set_container(TO_ELEM(res), pe) == PO_FAIL) {
1372 		(void) pool_component_destroy(pool_elem_comp(pe));
1373 		return (NULL);
1374 	}
1375 	/*
1376 	 * The plugins contain a list of default properties and their values
1377 	 * for resources. The resource returned, hence, is fully initialized.
1378 	 */
1379 	if ((default_props = provider_get_props(pe)) != NULL) {
1380 		int i;
1381 		for (i = 0; default_props[i].pp_pname != NULL; i++) {
1382 			if (prop_is_init(&default_props[i]) &&
1383 			    pool_put_any_property(pe,
1384 			    default_props[i].pp_pname,
1385 			    &default_props[i].pp_value) == PO_FAIL) {
1386 				(void) pool_component_destroy(
1387 				    pool_elem_comp(pe));
1388 				return (NULL);
1389 			}
1390 		}
1391 	}
1392 	/*
1393 	 * Set additional attributes/properties on component.
1394 	 */
1395 	pool_value_set_int64(&val, sys_id);
1396 	if (pool_put_any_ns_property(pe, c_sys_prop, &val) != PO_SUCCESS) {
1397 		(void) pool_component_destroy(pool_elem_comp(pe));
1398 		return (NULL);
1399 	}
1400 	if (snprintf(refbuf, KEY_BUFFER_SIZE, "%s_%lld",
1401 	    pool_elem_class_string(pe), sys_id) > KEY_BUFFER_SIZE) {
1402 		(void) pool_component_destroy(pool_elem_comp(pe));
1403 		return (NULL);
1404 	}
1405 	if (pool_value_set_string(&val, refbuf) != PO_SUCCESS) {
1406 		(void) pool_component_destroy(pool_elem_comp(pe));
1407 		return (NULL);
1408 	}
1409 	if (pool_put_any_ns_property(pe, c_ref_id, &val) != PO_SUCCESS) {
1410 		(void) pool_component_destroy(pool_elem_comp(pe));
1411 		return (NULL);
1412 	}
1413 	return (pool_elem_comp(pe));
1414 }
1415 
1416 /*
1417  * Return the location of a configuration.
1418  */
1419 const char *
1420 pool_conf_location(const pool_conf_t *conf)
1421 {
1422 	if (pool_conf_status(conf) == POF_INVALID) {
1423 		pool_seterror(POE_BADPARAM);
1424 		return (NULL);
1425 	}
1426 	return (conf->pc_location);
1427 }
1428 /*
1429  * Close a configuration, freeing all associated resources. Once a
1430  * configuration is closed, it can no longer be used.
1431  */
1432 int
1433 pool_conf_close(pool_conf_t *conf)
1434 {
1435 	int rv;
1436 
1437 	if (pool_conf_status(conf) == POF_INVALID) {
1438 		pool_seterror(POE_BADPARAM);
1439 		return (PO_FAIL);
1440 	}
1441 	rv = conf->pc_prov->pc_close(conf);
1442 	conf->pc_prov = NULL;
1443 	free((void *)conf->pc_location);
1444 	conf->pc_location = NULL;
1445 	conf->pc_state = POF_INVALID;
1446 	return (rv);
1447 }
1448 
1449 /*
1450  * Remove a configuration, freeing all associated resources. Once a
1451  * configuration is removed, it can no longer be accessed and is forever
1452  * gone.
1453  */
1454 int
1455 pool_conf_remove(pool_conf_t *conf)
1456 {
1457 	int rv;
1458 
1459 	if (pool_conf_status(conf) == POF_INVALID) {
1460 		pool_seterror(POE_BADPARAM);
1461 		return (PO_FAIL);
1462 	}
1463 	rv = conf->pc_prov->pc_remove(conf);
1464 	conf->pc_state = POF_INVALID;
1465 	return (rv);
1466 }
1467 
1468 /*
1469  * pool_conf_alloc() allocate the resources to represent a configuration.
1470  */
1471 pool_conf_t *
1472 pool_conf_alloc(void)
1473 {
1474 	pool_conf_t *conf;
1475 
1476 	if ((conf = calloc(1, sizeof (pool_conf_t))) == NULL) {
1477 		pool_seterror(POE_SYSTEM);
1478 		return (NULL);
1479 	}
1480 	conf->pc_state = POF_INVALID;
1481 	return (conf);
1482 }
1483 
1484 /*
1485  * pool_conf_free() frees the resources associated with a configuration.
1486  */
1487 void
1488 pool_conf_free(pool_conf_t *conf)
1489 {
1490 	free(conf);
1491 }
1492 
1493 /*
1494  * pool_conf_open() opens a configuration, establishing all required
1495  * connections to the data source.
1496  */
1497 int
1498 pool_conf_open(pool_conf_t *conf, const char *location, int oflags)
1499 {
1500 	/*
1501 	 * Since you can't do anything to a pool configuration without opening
1502 	 * it, this represents a good point to intialise structures that would
1503 	 * otherwise need to be initialised in a .init section.
1504 	 */
1505 	internal_init();
1506 
1507 	if (pool_conf_status(conf) != POF_INVALID) {
1508 		/*
1509 		 * Already opened configuration, return PO_FAIL
1510 		 */
1511 		pool_seterror(POE_BADPARAM);
1512 		return (PO_FAIL);
1513 	}
1514 	if (oflags & ~(PO_RDONLY | PO_RDWR | PO_CREAT | PO_DISCO | PO_UPDATE |
1515 	    PO_TEMP)) {
1516 		pool_seterror(POE_BADPARAM);
1517 		return (PO_FAIL);
1518 	}
1519 
1520 	/*
1521 	 * Creating a configuration implies read-write access, so make
1522 	 * sure that PO_RDWR is set in addition if PO_CREAT is set.
1523 	 */
1524 	if (oflags & PO_CREAT)
1525 		oflags |= PO_RDWR;
1526 
1527 	/* location is ignored when creating a temporary configuration */
1528 	if (oflags & PO_TEMP)
1529 		location = "";
1530 
1531 	if ((conf->pc_location = strdup(location)) == NULL) {
1532 		pool_seterror(POE_SYSTEM);
1533 		return (PO_FAIL);
1534 	}
1535 	/*
1536 	 * This is the crossover point into the actual data provider
1537 	 * implementation, allocate a data provider of the appropriate
1538 	 * type for your data storage medium. In this case it's either a kernel
1539 	 * or xml data provider. To use a different data provider, write some
1540 	 * code to implement all the required interfaces and then change the
1541 	 * following code to allocate a data provider which uses your new code.
1542 	 * All data provider routines can be static, apart from the allocation
1543 	 * routine.
1544 	 *
1545 	 * For temporary pools (PO_TEMP) we start with a copy of the current
1546 	 * dynamic configuration and do all of the updates in-memory.
1547 	 */
1548 	if (oflags & PO_TEMP) {
1549 		if (pool_knl_connection_alloc(conf, PO_TEMP) != PO_SUCCESS) {
1550 			conf->pc_state = POF_INVALID;
1551 			return (PO_FAIL);
1552 		}
1553 		/* set rdwr flag so we can updated the in-memory config. */
1554 		conf->pc_prov->pc_oflags |= PO_RDWR;
1555 
1556 	} else if (strcmp(location, pool_dynamic_location()) == 0) {
1557 		if (pool_knl_connection_alloc(conf, oflags) != PO_SUCCESS) {
1558 			conf->pc_state = POF_INVALID;
1559 			return (PO_FAIL);
1560 		}
1561 	} else {
1562 		if (pool_xml_connection_alloc(conf, oflags) != PO_SUCCESS) {
1563 			conf->pc_state = POF_INVALID;
1564 			return (PO_FAIL);
1565 		}
1566 	}
1567 	return (PO_SUCCESS);
1568 }
1569 
1570 /*
1571  * Rollback a configuration. This will undo all changes to the configuration
1572  * since the last time pool_conf_commit was called.
1573  */
1574 int
1575 pool_conf_rollback(pool_conf_t *conf)
1576 {
1577 	if (pool_conf_status(conf) == POF_INVALID) {
1578 		pool_seterror(POE_BADPARAM);
1579 		return (PO_FAIL);
1580 	}
1581 	return (conf->pc_prov->pc_rollback(conf));
1582 }
1583 
1584 /*
1585  * Commit a configuration. This will apply all changes to the
1586  * configuration to the permanent data store. The active parameter
1587  * indicates whether the configuration should be used to update the
1588  * dynamic configuration from the supplied (static) configuration or
1589  * whether it should be written back to persistent store.
1590  */
1591 int
1592 pool_conf_commit(pool_conf_t *conf, int active)
1593 {
1594 	int retval;
1595 
1596 	if (pool_conf_status(conf) == POF_INVALID) {
1597 		pool_seterror(POE_BADPARAM);
1598 		return (PO_FAIL);
1599 	}
1600 	if (active) {
1601 		int oflags;
1602 
1603 		if (conf_is_dynamic(conf) == PO_TRUE) {
1604 			pool_seterror(POE_BADPARAM);
1605 			return (PO_FAIL);
1606 		}
1607 		/*
1608 		 * Pretend that the configuration was opened PO_RDWR
1609 		 * so that a configuration which was opened PO_RDONLY
1610 		 * can be committed. The original flags are preserved
1611 		 * in oflags and restored after pool_conf_commit_sys()
1612 		 * returns.
1613 		 */
1614 		oflags = conf->pc_prov->pc_oflags;
1615 		conf->pc_prov->pc_oflags |= PO_RDWR;
1616 		retval = pool_conf_commit_sys(conf, active);
1617 		conf->pc_prov->pc_oflags = oflags;
1618 	} else {
1619 		/*
1620 		 * Write the configuration back to the backing store.
1621 		 */
1622 		retval =  conf->pc_prov->pc_commit(conf);
1623 	}
1624 	return (retval);
1625 }
1626 
1627 /*
1628  * Export a configuration. This will export a configuration in the specified
1629  * format (fmt) to the specified location.
1630  */
1631 int
1632 pool_conf_export(const pool_conf_t *conf, const char *location,
1633     pool_export_format_t fmt)
1634 {
1635 	if (pool_conf_status(conf) == POF_INVALID) {
1636 		pool_seterror(POE_BADPARAM);
1637 		return (PO_FAIL);
1638 	}
1639 	return (conf->pc_prov->pc_export(conf, location, fmt));
1640 }
1641 
1642 /*
1643  * Validate a configuration. This will validate a configuration at the
1644  * specified level.
1645  */
1646 int
1647 pool_conf_validate(const pool_conf_t *conf, pool_valid_level_t level)
1648 {
1649 	if (pool_conf_status(conf) == POF_INVALID) {
1650 		pool_seterror(POE_BADPARAM);
1651 		return (PO_FAIL);
1652 	}
1653 	return (conf->pc_prov->pc_validate(conf, level));
1654 }
1655 
1656 /*
1657  * Update the snapshot of a configuration. This can only be used on a
1658  * dynamic configuration.
1659  */
1660 int
1661 pool_conf_update(const pool_conf_t *conf, int *changed)
1662 {
1663 	if (pool_conf_status(conf) == POF_INVALID ||
1664 	    conf_is_dynamic(conf) == PO_FALSE) {
1665 		pool_seterror(POE_BADPARAM);
1666 		return (PO_FAIL);
1667 	}
1668 	/*
1669 	 * Since this function only makes sense for dynamic
1670 	 * configurations, just call directly into the appropriate
1671 	 * function. This could be added into the pool_connection_t
1672 	 * interface if it was ever required.
1673 	 */
1674 	if (changed)
1675 		*changed = 0;
1676 	return (pool_knl_update((pool_conf_t *)conf, changed));
1677 }
1678 
1679 /*
1680  * Walk the properties of the supplied elem, calling the user supplied
1681  * function repeatedly as long as the user function returns
1682  * PO_SUCCESS.
1683  */
1684 int
1685 pool_walk_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1686     int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1687 	pool_value_t *, void *))
1688 {
1689 	return (pool_walk_any_properties(conf, elem, arg, prop_callback, 0));
1690 }
1691 
1692 void
1693 free_value_list(int npvals, pool_value_t **pvals)
1694 {
1695 	int j;
1696 
1697 	for (j = 0; j < npvals; j++) {
1698 		if (pvals[j])
1699 			pool_value_free(pvals[j]);
1700 	}
1701 	free(pvals);
1702 }
1703 
1704 /*
1705  * Walk the properties of the supplied elem, calling the user supplied
1706  * function repeatedly as long as the user function returns
1707  * PO_SUCCESS.
1708  * The list of properties to be walked is retrieved from the element
1709  */
1710 int
1711 pool_walk_any_properties(pool_conf_t *conf, pool_elem_t *elem, void *arg,
1712     int (*prop_callback)(pool_conf_t *, pool_elem_t *, const char *,
1713 	pool_value_t *, void *), int any)
1714 {
1715 	pool_value_t **pvals;
1716 	int i;
1717 	const pool_prop_t *props = provider_get_props(elem);
1718 	uint_t npvals;
1719 
1720 	if (pool_conf_status(conf) == POF_INVALID) {
1721 		pool_seterror(POE_BADPARAM);
1722 		return (PO_FAIL);
1723 	}
1724 
1725 	if (props == NULL) {
1726 		pool_seterror(POE_INVALID_CONF);
1727 		return (PO_FAIL);
1728 	}
1729 
1730 	if ((pvals = elem->pe_get_props(elem, &npvals)) == NULL)
1731 		return (PO_FAIL);
1732 
1733 	/*
1734 	 * Now walk the managed properties. As we find managed
1735 	 * properties removed them from the list of all properties to
1736 	 * prevent duplication.
1737 	 */
1738 	for (i = 0;  props[i].pp_pname != NULL; i++) {
1739 		int j;
1740 
1741 		/*
1742 		 * Special processing for type
1743 		 */
1744 		if (strcmp(props[i].pp_pname, c_type) == 0) {
1745 			pool_value_t val = POOL_VALUE_INITIALIZER;
1746 
1747 			if (pool_value_set_name(&val, props[i].pp_pname) ==
1748 			    PO_FAIL) {
1749 				free_value_list(npvals, pvals);
1750 				return (PO_FAIL);
1751 			}
1752 			if (props[i].pp_op.ppo_get_value(elem, &val) ==
1753 			    PO_FAIL) {
1754 				free_value_list(npvals, pvals);
1755 				return (PO_FAIL);
1756 			}
1757 			if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1758 				if (prop_callback(conf, elem, props[i].pp_pname,
1759 				    &val, arg) != PO_SUCCESS) {
1760 					free_value_list(npvals, pvals);
1761 					pool_seterror(POE_BADPARAM);
1762 					return (PO_FAIL);
1763 				}
1764 			}
1765 			continue;
1766 		}
1767 
1768 		for (j = 0; j < npvals; j++) {
1769 			if (pvals[j] && strcmp(pool_value_get_name(pvals[j]),
1770 			    props[i].pp_pname) == 0)
1771 				break;
1772 		}
1773 		/*
1774 		 * If we have found the property, then j < npvals. Process it
1775 		 * according to our property attributes. Otherwise, it's not
1776 		 * a managed property, so just ignore it until later.
1777 		 */
1778 		if (j < npvals) {
1779 			if (any == 1 || prop_is_hidden(&props[i]) == PO_FALSE) {
1780 				if (props[i].pp_op.ppo_get_value) {
1781 					if (pool_value_set_name(pvals[j],
1782 					props[i].pp_pname) == PO_FAIL) {
1783 						free_value_list(npvals, pvals);
1784 						return (PO_FAIL);
1785 					}
1786 					if (props[i].pp_op.ppo_get_value(elem,
1787 					    pvals[j]) == PO_FAIL) {
1788 						free_value_list(npvals, pvals);
1789 						return (PO_FAIL);
1790 					}
1791 				}
1792 				if (prop_callback(conf, elem, props[i].pp_pname,
1793 				    pvals[j], arg) != PO_SUCCESS) {
1794 					free_value_list(npvals, pvals);
1795 					pool_seterror(POE_BADPARAM);
1796 					return (PO_FAIL);
1797 				}
1798 			}
1799 			pool_value_free(pvals[j]);
1800 			pvals[j] = NULL;
1801 		}
1802 	}
1803 	for (i = 0;  i < npvals; i++) {
1804 		if (pvals[i]) {
1805 			const char *name = pool_value_get_name(pvals[i]);
1806 			char *qname = strrchr(name, '.');
1807 			if ((qname && qname[1] != '_') ||
1808 			    (!qname && name[0] != '_')) {
1809 				if (prop_callback(conf, elem, name, pvals[i],
1810 				    arg) != PO_SUCCESS) {
1811 					free_value_list(npvals, pvals);
1812 					pool_seterror(POE_BADPARAM);
1813 					return (PO_FAIL);
1814 				}
1815 			}
1816 			pool_value_free(pvals[i]);
1817 			pvals[i] = NULL;
1818 		}
1819 	}
1820 	free(pvals);
1821 	return (PO_SUCCESS);
1822 }
1823 
1824 /*
1825  * Return a pool, searching the supplied configuration for a pool with the
1826  * supplied name. The search is case sensitive.
1827  */
1828 pool_t *
1829 pool_get_pool(const pool_conf_t *conf, const char *name)
1830 {
1831 	pool_value_t *props[] = { NULL, NULL };
1832 	pool_t **rs;
1833 	pool_t *ret;
1834 	uint_t size = 0;
1835 	pool_value_t val = POOL_VALUE_INITIALIZER;
1836 
1837 	props[0] = &val;
1838 
1839 	if (pool_conf_status(conf) == POF_INVALID) {
1840 		pool_seterror(POE_BADPARAM);
1841 		return (NULL);
1842 	}
1843 
1844 	if (pool_value_set_name(props[0], "pool.name") != PO_SUCCESS ||
1845 	    pool_value_set_string(props[0], name) != PO_SUCCESS) {
1846 		return (NULL);
1847 	}
1848 	rs = pool_query_pools(conf, &size, props);
1849 	if (rs == NULL) { /* Can't find a pool to match the name */
1850 		return (NULL);
1851 	}
1852 	if (size != 1) {
1853 		free(rs);
1854 		pool_seterror(POE_INVALID_CONF);
1855 		return (NULL);
1856 	}
1857 	ret = rs[0];
1858 	free(rs);
1859 	return (ret);
1860 }
1861 
1862 /*
1863  * Return a result set of pools, searching the supplied configuration
1864  * for pools which match the supplied property criteria. props is a null
1865  * terminated list of properties which will be used to match qualifying
1866  * pools. size is updated with the size of the pool
1867  */
1868 pool_t **
1869 pool_query_pools(const pool_conf_t *conf, uint_t *size, pool_value_t **props)
1870 {
1871 	pool_result_set_t *rs;
1872 	pool_elem_t *pe;
1873 	pool_t **result = NULL;
1874 	int i = 0;
1875 
1876 	if (pool_conf_status(conf) == POF_INVALID) {
1877 		pool_seterror(POE_BADPARAM);
1878 		return (NULL);
1879 	}
1880 	rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_POOL, props);
1881 	if (rs == NULL) {
1882 		return (NULL);
1883 	}
1884 	if ((*size = pool_rs_count(rs)) == 0) {
1885 		(void) pool_rs_close(rs);
1886 		return (NULL);
1887 	}
1888 	if ((result = malloc(sizeof (pool_t *) * (*size + 1))) == NULL) {
1889 		pool_seterror(POE_SYSTEM);
1890 		(void) pool_rs_close(rs);
1891 		return (NULL);
1892 	}
1893 	(void) memset(result, 0, sizeof (pool_t *) * (*size + 1));
1894 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
1895 		if (pool_elem_class(pe) != PEC_POOL) {
1896 			pool_seterror(POE_INVALID_CONF);
1897 			free(result);
1898 			(void) pool_rs_close(rs);
1899 			return (NULL);
1900 		}
1901 		result[i++] = pool_elem_pool(pe);
1902 	}
1903 	(void) pool_rs_close(rs);
1904 	return (result);
1905 }
1906 
1907 /*
1908  * Return an res, searching the supplied configuration for an res with the
1909  * supplied name. The search is case sensitive.
1910  */
1911 pool_resource_t *
1912 pool_get_resource(const pool_conf_t *conf, const char *sz_type,
1913     const char *name)
1914 {
1915 	pool_value_t *props[] = { NULL, NULL, NULL };
1916 	pool_resource_t **rs;
1917 	pool_resource_t *ret;
1918 	uint_t size = 0;
1919 	char_buf_t *cb = NULL;
1920 	pool_value_t val0 = POOL_VALUE_INITIALIZER;
1921 	pool_value_t val1 = POOL_VALUE_INITIALIZER;
1922 
1923 	if (pool_conf_status(conf) == POF_INVALID) {
1924 		pool_seterror(POE_BADPARAM);
1925 		return (NULL);
1926 	}
1927 
1928 	if (sz_type == NULL) {
1929 		pool_seterror(POE_BADPARAM);
1930 		return (NULL);
1931 	}
1932 
1933 	props[0] = &val0;
1934 	props[1] = &val1;
1935 
1936 	if (pool_value_set_string(props[0], sz_type) != PO_SUCCESS ||
1937 	    pool_value_set_name(props[0], c_type) != PO_SUCCESS)
1938 		return (NULL);
1939 
1940 	if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
1941 		return (NULL);
1942 	}
1943 	if (set_char_buf(cb, "%s.name", sz_type) != PO_SUCCESS) {
1944 		free_char_buf(cb);
1945 		return (NULL);
1946 	}
1947 	if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
1948 		free_char_buf(cb);
1949 		return (NULL);
1950 	}
1951 	if (pool_value_set_string(props[1], name) != PO_SUCCESS) {
1952 		free_char_buf(cb);
1953 		return (NULL);
1954 	}
1955 	free_char_buf(cb);
1956 	rs = pool_query_resources(conf, &size, props);
1957 	if (rs == NULL) {
1958 		return (NULL);
1959 	}
1960 	if (size != 1) {
1961 		free(rs);
1962 		pool_seterror(POE_INVALID_CONF);
1963 		return (NULL);
1964 	}
1965 	ret = rs[0];
1966 	free(rs);
1967 	return (ret);
1968 }
1969 
1970 /*
1971  * Return a result set of res (actually as pool_elem_ts), searching the
1972  * supplied configuration for res which match the supplied property
1973  * criteria. props is a null terminated list of properties which will be used
1974  * to match qualifying res.
1975  */
1976 pool_resource_t **
1977 pool_query_resources(const pool_conf_t *conf, uint_t *size,
1978     pool_value_t **props)
1979 {
1980 	pool_result_set_t *rs;
1981 	pool_elem_t *pe;
1982 	pool_resource_t **result = NULL;
1983 	int i = 0;
1984 
1985 	if (pool_conf_status(conf) == POF_INVALID) {
1986 		pool_seterror(POE_BADPARAM);
1987 		return (NULL);
1988 	}
1989 
1990 	*size = 0;
1991 
1992 	rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_RES, props);
1993 	if (rs == NULL) {
1994 		return (NULL);
1995 	}
1996 	if ((*size = pool_rs_count(rs)) == 0) {
1997 		(void) pool_rs_close(rs);
1998 		return (NULL);
1999 	}
2000 	if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
2001 	    == NULL) {
2002 		pool_seterror(POE_SYSTEM);
2003 		(void) pool_rs_close(rs);
2004 		return (NULL);
2005 	}
2006 	(void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
2007 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2008 		if (pool_elem_class(pe) != PEC_RES_COMP &&
2009 		    pool_elem_class(pe) != PEC_RES_AGG) {
2010 			pool_seterror(POE_INVALID_CONF);
2011 			free(result);
2012 			(void) pool_rs_close(rs);
2013 			return (NULL);
2014 		}
2015 		result[i++] = pool_elem_res(pe);
2016 	}
2017 	(void) pool_rs_close(rs);
2018 	return (result);
2019 }
2020 
2021 /*
2022  * Return a result set of comp (actually as pool_elem_ts), searching the
2023  * supplied configuration for comp which match the supplied property
2024  * criteria. props is a null terminated list of properties which will be used
2025  * to match qualifying comp.
2026  */
2027 pool_component_t **
2028 pool_query_components(const pool_conf_t *conf, uint_t *size,
2029     pool_value_t **props)
2030 {
2031 	return (pool_query_resource_components(conf, NULL, size, props));
2032 }
2033 
2034 /*
2035  * Destroy a pool. If the pool cannot be found or removed an error is
2036  * returned. This is basically a wrapper around pool_elem_remove to ensure
2037  * some type safety for the pool subtype.
2038  */
2039 int
2040 pool_destroy(pool_conf_t *conf, pool_t *pp)
2041 {
2042 	pool_elem_t *pe;
2043 
2044 	if (pool_conf_check(conf) != PO_SUCCESS)
2045 		return (PO_FAIL);
2046 
2047 	pe = TO_ELEM(pp);
2048 
2049 	/*
2050 	 * Cannot destroy the default pool.
2051 	 */
2052 	if (elem_is_default(pe) == PO_TRUE) {
2053 		pool_seterror(POE_BADPARAM);
2054 		return (PO_FAIL);
2055 	}
2056 	if (pool_elem_remove(pe) != PO_SUCCESS)
2057 		return (PO_FAIL);
2058 	return (PO_SUCCESS);
2059 }
2060 
2061 /*
2062  * Destroy an res. If the res cannot be found or removed an error is
2063  * returned. This is basically a wrapper around pool_elem_remove to ensure
2064  * some type safety for the res subtype.
2065  */
2066 int
2067 pool_resource_destroy(pool_conf_t *conf, pool_resource_t *prs)
2068 {
2069 	pool_elem_t *pe;
2070 	pool_component_t **rl;
2071 	uint_t res_size;
2072 	pool_t **pl;
2073 	uint_t npool;
2074 	int i;
2075 
2076 	if (pool_conf_check(conf) != PO_SUCCESS)
2077 		return (PO_FAIL);
2078 
2079 	pe = TO_ELEM(prs);
2080 
2081 	if (resource_is_system(prs) == PO_TRUE) {
2082 		pool_seterror(POE_BADPARAM);
2083 		return (PO_FAIL);
2084 	}
2085 	/*
2086 	 * Walk all the pools and dissociate any pools which are using
2087 	 * this resource.
2088 	 */
2089 	if ((pl = pool_query_pools(conf, &npool, NULL)) != NULL) {
2090 		for (i = 0; i < npool; i++) {
2091 			pool_resource_t **rl;
2092 			uint_t nres;
2093 			int j;
2094 
2095 			if ((rl = pool_query_pool_resources(conf, pl[i], &nres,
2096 			    NULL)) != NULL) {
2097 				for (j = 0; j < nres; j++) {
2098 					if (rl[j] == prs) {
2099 						if (pool_dissociate(conf, pl[i],
2100 						    rl[j]) != PO_SUCCESS) {
2101 							free(rl);
2102 							free(pl);
2103 							return (PO_FAIL);
2104 						}
2105 						break;
2106 					}
2107 				}
2108 			free(rl);
2109 			}
2110 		}
2111 		free(pl);
2112 	}
2113 	if (pe->pe_class == PEC_RES_COMP) {
2114 		pool_resource_t *default_set_res;
2115 
2116 		/*
2117 		 * Use the xtransfer option to move comp around
2118 		 */
2119 		default_set_res = (pool_resource_t *)get_default_resource(prs);
2120 
2121 		if ((rl = pool_query_resource_components(conf, prs, &res_size,
2122 		    NULL)) != NULL) {
2123 			int ostate = conf->pc_state;
2124 			conf->pc_state = POF_DESTROY;
2125 			if (pool_resource_xtransfer(conf, prs, default_set_res,
2126 			    rl) == PO_FAIL) {
2127 				free(rl);
2128 				conf->pc_state = ostate;
2129 				return (PO_FAIL);
2130 			}
2131 			conf->pc_state = ostate;
2132 			free(rl);
2133 		}
2134 	}
2135 	if (pool_elem_remove(pe) != PO_SUCCESS)
2136 		return (PO_FAIL);
2137 	return (PO_SUCCESS);
2138 }
2139 
2140 /*
2141  * Destroy a comp. If the comp cannot be found or removed an error is
2142  * returned. This is basically a wrapper around pool_elem_remove to ensure
2143  * some type safety for the comp subtype.
2144  */
2145 int
2146 pool_component_destroy(pool_component_t *pr)
2147 {
2148 	pool_elem_t *pe = TO_ELEM(pr);
2149 
2150 	if (pool_elem_remove(pe) != PO_SUCCESS)
2151 		return (PO_FAIL);
2152 	return (PO_SUCCESS);
2153 }
2154 
2155 /*
2156  * Remove a pool_elem_t from a configuration. This has been "hidden" away as
2157  * a static routine since the only elements which are currently being removed
2158  * are pools, res & comp and the wrapper functions above provide type-safe
2159  * access. However, if there is a need to remove other types of elements
2160  * then this could be promoted to pool_impl.h or more wrappers could
2161  * be added to pool_impl.h.
2162  */
2163 int
2164 pool_elem_remove(pool_elem_t *pe)
2165 {
2166 	return (pe->pe_remove(pe));
2167 }
2168 
2169 /*
2170  * Execute a query to search for a qualifying set of elements.
2171  */
2172 pool_result_set_t *
2173 pool_exec_query(const pool_conf_t *conf, const pool_elem_t *src,
2174     const char *src_attr, pool_elem_class_t classes, pool_value_t **props)
2175 {
2176 	return (conf->pc_prov->pc_exec_query(conf, src, src_attr, classes,
2177 	    props));
2178 }
2179 
2180 /*
2181  * Get the next result from a result set of elements.
2182  */
2183 pool_elem_t *
2184 pool_rs_next(pool_result_set_t *set)
2185 {
2186 	return (set->prs_next(set));
2187 }
2188 
2189 /*
2190  * Get the previous result from a result set of elements.
2191  */
2192 pool_elem_t *
2193 pool_rs_prev(pool_result_set_t *set)
2194 {
2195 	return (set->prs_prev(set));
2196 }
2197 
2198 /*
2199  * Get the first result from a result set of elements.
2200  */
2201 pool_elem_t *
2202 pool_rs_first(pool_result_set_t *set)
2203 {
2204 	return (set->prs_first(set));
2205 }
2206 
2207 /*
2208  * Get the last result from a result set of elements.
2209  */
2210 pool_elem_t *
2211 pool_rs_last(pool_result_set_t *set)
2212 {
2213 	return (set->prs_last(set));
2214 }
2215 
2216 
2217 /*
2218  * Get the count for a result set of elements.
2219  */
2220 int
2221 pool_rs_count(pool_result_set_t *set)
2222 {
2223 	return (set->prs_count(set));
2224 }
2225 
2226 /*
2227  * Get the index for a result set of elements.
2228  */
2229 int
2230 pool_rs_get_index(pool_result_set_t *set)
2231 {
2232 	return (set->prs_get_index(set));
2233 }
2234 
2235 /*
2236  * Set the index for a result set of elements.
2237  */
2238 int
2239 pool_rs_set_index(pool_result_set_t *set, int index)
2240 {
2241 	return (set->prs_set_index(set, index));
2242 }
2243 
2244 /*
2245  * Close a result set of elements, freeing all associated resources.
2246  */
2247 int
2248 pool_rs_close(pool_result_set_t *set)
2249 {
2250 	return (set->prs_close(set));
2251 }
2252 
2253 /*
2254  * When transferring resource components using pool_resource_transfer,
2255  * this function is invoked to choose which actual components will be
2256  * transferred.
2257  */
2258 int
2259 choose_components(pool_resource_t *src, pool_resource_t *dst, uint64_t size)
2260 {
2261 	pool_component_t **components = NULL, *moved[] = { NULL, NULL };
2262 	int i;
2263 	uint_t ncomponent;
2264 	pool_conf_t *conf = TO_CONF(TO_ELEM(src));
2265 
2266 	if (size == 0)
2267 		return (PO_SUCCESS);
2268 	/*
2269 	 * Get the component list from our src component.
2270 	 */
2271 	if ((components = pool_query_resource_components(conf, src, &ncomponent,
2272 	    NULL)) == NULL) {
2273 		pool_seterror(POE_BADPARAM);
2274 		return (PO_FAIL);
2275 	}
2276 	qsort(components, ncomponent, sizeof (pool_elem_t *),
2277 	    qsort_elem_compare);
2278 	/*
2279 	 * Components that aren't specifically requested by the resource
2280 	 * should be transferred out first.
2281 	 */
2282 	for (i = 0; size > 0 && components[i] != NULL; i++) {
2283 		if (!cpu_is_requested(components[i])) {
2284 			moved[0] = components[i];
2285 			if (pool_resource_xtransfer(conf, src, dst, moved) ==
2286 			    PO_SUCCESS) {
2287 				size--;
2288 			}
2289 		}
2290 	}
2291 
2292 	/*
2293 	 * If we couldn't find enough "un-requested" components, select random
2294 	 * requested components.
2295 	 */
2296 	for (i = 0; size > 0 && components[i] != NULL; i++) {
2297 		if (cpu_is_requested(components[i])) {
2298 			moved[0] = components[i];
2299 			if (pool_resource_xtransfer(conf, src, dst, moved) ==
2300 			    PO_SUCCESS) {
2301 				size--;
2302 			}
2303 		}
2304 	}
2305 
2306 	free(components);
2307 	/*
2308 	 * If we couldn't transfer out all the resources we asked for, then
2309 	 * return error.
2310 	 */
2311 	return (size == 0 ? PO_SUCCESS : PO_FAIL);
2312 }
2313 
2314 /*
2315  * Common processing for a resource transfer (xfer or xxfer).
2316  *
2317  * - Return XFER_CONTINUE if the transfer should proceeed
2318  * - Return XFER_FAIL if the transfer should be stopped in failure
2319  * - Return XFER_SUCCESS if the transfer should be stopped in success
2320  */
2321 int
2322 setup_transfer(pool_conf_t *conf, pool_resource_t *src, pool_resource_t *tgt,
2323     uint64_t size, uint64_t *src_size, uint64_t *tgt_size)
2324 {
2325 	uint64_t src_min;
2326 	uint64_t tgt_max;
2327 
2328 	if (pool_conf_check(conf) != PO_SUCCESS)
2329 		return (XFER_FAIL);
2330 
2331 	/*
2332 	 * Makes sure the two resources are of the same type
2333 	 */
2334 	if (pool_resource_elem_class(TO_ELEM(src)) !=
2335 	    pool_resource_elem_class(TO_ELEM(tgt))) {
2336 		pool_seterror(POE_BADPARAM);
2337 		return (XFER_FAIL);
2338 	}
2339 
2340 	/*
2341 	 * Transferring to yourself is a no-op
2342 	 */
2343 	if (src == tgt)
2344 		return (XFER_SUCCESS);
2345 
2346 	/*
2347 	 * Transferring nothing is a no-op
2348 	 */
2349 	if (size == 0)
2350 		return (XFER_SUCCESS);
2351 
2352 	if (resource_get_min(src, &src_min) != PO_SUCCESS ||
2353 	    resource_get_size(src, src_size) != PO_SUCCESS ||
2354 	    resource_get_max(tgt, &tgt_max) != PO_SUCCESS ||
2355 	    resource_get_size(tgt, tgt_size) != PO_SUCCESS) {
2356 		pool_seterror(POE_BADPARAM);
2357 		return (XFER_FAIL);
2358 	}
2359 	if (pool_conf_status(conf) != POF_DESTROY) {
2360 		/*
2361 		 * src_size - donating >= src.min
2362 		 * size + receiving <= tgt.max (except for default)
2363 		 */
2364 #ifdef DEBUG
2365 		dprintf("conf is %s\n", pool_conf_location(conf));
2366 		dprintf("setup_transfer: src_size %llu\n", *src_size);
2367 		pool_elem_dprintf(TO_ELEM(src));
2368 		dprintf("setup_transfer: tgt_size %llu\n", *tgt_size);
2369 		pool_elem_dprintf(TO_ELEM(tgt));
2370 #endif	/* DEBUG */
2371 		if (*src_size - size < src_min ||
2372 		    (resource_is_default(tgt) == PO_FALSE &&
2373 			*tgt_size + size > tgt_max)) {
2374 			pool_seterror(POE_INVALID_CONF);
2375 			return (XFER_FAIL);
2376 		}
2377 	}
2378 	return (XFER_CONTINUE);
2379 }
2380 
2381 /*
2382  * Transfer resource quantities from one resource set to another.
2383  */
2384 int
2385 pool_resource_transfer(pool_conf_t *conf, pool_resource_t *src,
2386     pool_resource_t *tgt, uint64_t size)
2387 {
2388 	uint64_t src_size;
2389 	uint64_t tgt_size;
2390 	int ret;
2391 
2392 	if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2393 	    != XFER_CONTINUE)
2394 		return (ret);
2395 	/*
2396 	 * If this resource is a res_comp we must call move components
2397 	 */
2398 	if (pool_elem_class(TO_ELEM(src)) == PEC_RES_COMP)
2399 		return (choose_components(src, tgt, size));
2400 	/*
2401 	 * Now do the transfer.
2402 	 */
2403 	ret = conf->pc_prov->pc_res_xfer(src, tgt, size);
2404 	/*
2405 	 * Modify the sizes of the resource sets if the process was
2406 	 * successful
2407 	 */
2408 	if (ret == PO_SUCCESS) {
2409 		pool_value_t val = POOL_VALUE_INITIALIZER;
2410 
2411 		src_size -= size;
2412 		tgt_size += size;
2413 		pool_value_set_uint64(&val, src_size);
2414 		(void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2415 		    &val);
2416 		pool_value_set_uint64(&val, tgt_size);
2417 		(void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2418 		    &val);
2419 	}
2420 	return (ret);
2421 }
2422 
2423 /*
2424  * Transfer resource components from one resource set to another.
2425  */
2426 int
2427 pool_resource_xtransfer(pool_conf_t *conf, pool_resource_t *src,
2428     pool_resource_t *tgt,
2429     pool_component_t **rl)
2430 {
2431 	int i;
2432 	uint64_t src_size;
2433 	uint64_t tgt_size;
2434 	uint64_t size;
2435 	int ret;
2436 
2437 	/*
2438 	 * Make sure the components are all contained in 'src'. This
2439 	 * processing must be done before setup_transfer so that size
2440 	 * is known.
2441 	 */
2442 	for (i = 0; rl[i] != NULL; i++) {
2443 #ifdef DEBUG
2444 		dprintf("resource xtransfer\n");
2445 		dprintf("in conf %s\n", pool_conf_location(conf));
2446 		dprintf("transferring component\n");
2447 		pool_elem_dprintf(TO_ELEM(rl[i]));
2448 		dprintf("from\n");
2449 		pool_elem_dprintf(TO_ELEM(src));
2450 		dprintf("to\n");
2451 		pool_elem_dprintf(TO_ELEM(tgt));
2452 #endif	/* DEBUG */
2453 
2454 		if (pool_get_owning_resource(conf, rl[i]) != src) {
2455 			pool_seterror(POE_BADPARAM);
2456 			return (PO_FAIL);
2457 		}
2458 	}
2459 
2460 	size = (uint64_t)i;
2461 
2462 	if ((ret = setup_transfer(conf, src, tgt, size, &src_size, &tgt_size))
2463 	    != XFER_CONTINUE)
2464 		return (ret);
2465 
2466 	ret = conf->pc_prov->pc_res_xxfer(src, tgt, rl);
2467 	/*
2468 	 * Modify the sizes of the resource sets if the process was
2469 	 * successful
2470 	 */
2471 	if (ret == PO_SUCCESS) {
2472 		pool_value_t val = POOL_VALUE_INITIALIZER;
2473 
2474 #ifdef DEBUG
2475 		dprintf("src_size %llu\n", src_size);
2476 		dprintf("tgt_size %llu\n", tgt_size);
2477 		dprintf("size %llu\n", size);
2478 #endif	/* DEBUG */
2479 		src_size -= size;
2480 		tgt_size += size;
2481 		pool_value_set_uint64(&val, src_size);
2482 		(void) pool_put_any_ns_property(TO_ELEM(src), c_size_prop,
2483 		    &val);
2484 		pool_value_set_uint64(&val, tgt_size);
2485 		(void) pool_put_any_ns_property(TO_ELEM(tgt), c_size_prop,
2486 		    &val);
2487 	}
2488 	return (ret);
2489 }
2490 
2491 /*
2492  * Find the owning resource for a resource component.
2493  */
2494 pool_resource_t *
2495 pool_get_owning_resource(const pool_conf_t *conf, const pool_component_t *comp)
2496 {
2497 	if (pool_conf_status(conf) == POF_INVALID) {
2498 		pool_seterror(POE_BADPARAM);
2499 		return (NULL);
2500 	}
2501 	return (pool_elem_res(pool_get_container(TO_ELEM(comp))));
2502 }
2503 
2504 /*
2505  * pool_get_container() returns the container of pc.
2506  */
2507 pool_elem_t *
2508 pool_get_container(const pool_elem_t *pc)
2509 {
2510 	return (pc->pe_get_container(pc));
2511 }
2512 
2513 /*
2514  * pool_set_container() moves pc so that it is contained by pp.
2515  *
2516  * Returns PO_SUCCESS/PO_FAIL
2517  */
2518 int
2519 pool_set_container(pool_elem_t *pp, pool_elem_t *pc)
2520 {
2521 	return (pc->pe_set_container(pp, pc));
2522 }
2523 
2524 /*
2525  * Conversion routines for converting to and from elem and it's various
2526  * subtypes of system, pool, res and comp.
2527  */
2528 pool_elem_t *
2529 pool_system_elem(const pool_system_t *ph)
2530 {
2531 	return ((pool_elem_t *)ph);
2532 }
2533 
2534 pool_elem_t *
2535 pool_conf_to_elem(const pool_conf_t *conf)
2536 {
2537 	pool_system_t *sys;
2538 
2539 	if (pool_conf_status(conf) == POF_INVALID) {
2540 		pool_seterror(POE_BADPARAM);
2541 		return (NULL);
2542 	}
2543 	if ((sys = pool_conf_system(conf)) == NULL) {
2544 		pool_seterror(POE_BADPARAM);
2545 		return (NULL);
2546 	}
2547 	return (pool_system_elem(sys));
2548 }
2549 
2550 pool_elem_t *
2551 pool_to_elem(const pool_conf_t *conf, const pool_t *pp)
2552 {
2553 	if (pool_conf_status(conf) == POF_INVALID) {
2554 		pool_seterror(POE_BADPARAM);
2555 		return (NULL);
2556 	}
2557 	return ((pool_elem_t *)pp);
2558 }
2559 
2560 pool_elem_t *
2561 pool_resource_to_elem(const pool_conf_t *conf, const pool_resource_t *prs)
2562 {
2563 	if (pool_conf_status(conf) == POF_INVALID) {
2564 		pool_seterror(POE_BADPARAM);
2565 		return (NULL);
2566 	}
2567 	return ((pool_elem_t *)prs);
2568 }
2569 
2570 pool_elem_t *
2571 pool_component_to_elem(const pool_conf_t *conf, const pool_component_t *pr)
2572 {
2573 	if (pool_conf_status(conf) == POF_INVALID) {
2574 		pool_seterror(POE_BADPARAM);
2575 		return (NULL);
2576 	}
2577 	return ((pool_elem_t *)pr);
2578 }
2579 
2580 /*
2581  * Walk all the pools of the configuration calling the user supplied function
2582  * as long as the user function continues to return PO_TRUE
2583  */
2584 int
2585 pool_walk_pools(pool_conf_t *conf, void *arg,
2586     int (*callback)(pool_conf_t *conf, pool_t *pool, void *arg))
2587 {
2588 	pool_t **rs;
2589 	int i;
2590 	uint_t size;
2591 	int error = PO_SUCCESS;
2592 
2593 	if (pool_conf_status(conf) == POF_INVALID) {
2594 		pool_seterror(POE_BADPARAM);
2595 		return (PO_FAIL);
2596 	}
2597 
2598 	if ((rs = pool_query_pools(conf, &size, NULL)) == NULL) /* None */
2599 		return (PO_SUCCESS);
2600 	for (i = 0; i < size; i++)
2601 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2602 			error = PO_FAIL;
2603 			break;
2604 		}
2605 	free(rs);
2606 	return (error);
2607 }
2608 
2609 /*
2610  * Walk all the comp of the res calling the user supplied function
2611  * as long as the user function continues to return PO_TRUE
2612  */
2613 int
2614 pool_walk_components(pool_conf_t *conf, pool_resource_t *prs, void *arg,
2615     int (*callback)(pool_conf_t *conf, pool_component_t *pr, void *arg))
2616 {
2617 	pool_component_t **rs;
2618 	int i;
2619 	uint_t size;
2620 	int error = PO_SUCCESS;
2621 
2622 	if (pool_conf_status(conf) == POF_INVALID) {
2623 		pool_seterror(POE_BADPARAM);
2624 		return (PO_FAIL);
2625 	}
2626 
2627 	if ((rs = pool_query_resource_components(conf, prs, &size, NULL)) ==
2628 	    NULL)
2629 		return (PO_SUCCESS); /* None */
2630 	for (i = 0; i < size; i++)
2631 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2632 			error = PO_FAIL;
2633 			break;
2634 		}
2635 	free(rs);
2636 	return (error);
2637 }
2638 
2639 /*
2640  * Return an array of all matching res for the supplied pool.
2641  */
2642 pool_resource_t **
2643 pool_query_pool_resources(const pool_conf_t *conf, const pool_t *pp,
2644     uint_t *size, pool_value_t **props)
2645 {
2646 	pool_result_set_t *rs;
2647 	pool_elem_t *pe;
2648 	pool_resource_t **result = NULL;
2649 	int i = 0;
2650 
2651 	if (pool_conf_status(conf) == POF_INVALID) {
2652 		pool_seterror(POE_BADPARAM);
2653 		return (NULL);
2654 	}
2655 
2656 	pe = TO_ELEM(pp);
2657 
2658 	rs = pool_exec_query(conf, pe, "res", PEC_QRY_RES, props);
2659 	if (rs == NULL) {
2660 		return (NULL);
2661 	}
2662 	if ((*size = pool_rs_count(rs)) == 0) {
2663 		(void) pool_rs_close(rs);
2664 		return (NULL);
2665 	}
2666 	if ((result = malloc(sizeof (pool_resource_t *) * (*size + 1)))
2667 	    == NULL) {
2668 		pool_seterror(POE_SYSTEM);
2669 		(void) pool_rs_close(rs);
2670 		return (NULL);
2671 	}
2672 	(void) memset(result, 0, sizeof (pool_resource_t *) * (*size + 1));
2673 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2674 		if (pool_elem_class(pe) != PEC_RES_COMP &&
2675 		    pool_elem_class(pe) != PEC_RES_AGG) {
2676 			pool_seterror(POE_INVALID_CONF);
2677 			free(result);
2678 			(void) pool_rs_close(rs);
2679 			return (NULL);
2680 		}
2681 		result[i++] = pool_elem_res(pe);
2682 	}
2683 	(void) pool_rs_close(rs);
2684 	return (result);
2685 }
2686 
2687 /*
2688  * Walk all the res of the pool calling the user supplied function
2689  * as long as the user function continues to return PO_TRUE
2690  */
2691 int
2692 pool_walk_resources(pool_conf_t *conf, pool_t *pp, void *arg,
2693     int (*callback)(pool_conf_t *, pool_resource_t *, void *))
2694 {
2695 	pool_resource_t **rs;
2696 	int i;
2697 	uint_t size;
2698 	int error = PO_SUCCESS;
2699 
2700 	if (pool_conf_status(conf) == POF_INVALID) {
2701 		pool_seterror(POE_BADPARAM);
2702 		return (PO_FAIL);
2703 	}
2704 	if ((rs = pool_query_pool_resources(conf, pp, &size, NULL)) == NULL)
2705 		return (PO_SUCCESS); /* None */
2706 	for (i = 0; i < size; i++)
2707 		if (callback(conf, rs[i], arg) != PO_SUCCESS) {
2708 			error = PO_FAIL;
2709 			break;
2710 		}
2711 	free(rs);
2712 	return (error);
2713 }
2714 
2715 /*
2716  * Return a result set of all comp for the supplied res.
2717  */
2718 pool_component_t **
2719 pool_query_resource_components(const pool_conf_t *conf,
2720     const pool_resource_t *prs, uint_t *size, pool_value_t **props)
2721 {
2722 	pool_result_set_t *rs;
2723 	pool_elem_t *pe;
2724 	pool_component_t **result = NULL;
2725 	int i = 0;
2726 
2727 	if (pool_conf_status(conf) == POF_INVALID) {
2728 		pool_seterror(POE_BADPARAM);
2729 		return (NULL);
2730 	}
2731 	pe = TO_ELEM(prs);
2732 
2733 	rs = pool_exec_query(conf, pe, NULL, PEC_QRY_COMP, props);
2734 	if (rs == NULL) {
2735 		return (NULL);
2736 	}
2737 	if ((*size = pool_rs_count(rs)) == 0) {
2738 		(void) pool_rs_close(rs);
2739 		return (NULL);
2740 	}
2741 	if ((result = malloc(sizeof (pool_component_t *) * (*size + 1)))
2742 	    == NULL) {
2743 		pool_seterror(POE_SYSTEM);
2744 		(void) pool_rs_close(rs);
2745 		return (NULL);
2746 	}
2747 	(void) memset(result, 0, sizeof (pool_component_t *) * (*size + 1));
2748 	for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
2749 		if (pool_elem_class(pe) != PEC_COMP) {
2750 			pool_seterror(POE_INVALID_CONF);
2751 			free(result);
2752 			(void) pool_rs_close(rs);
2753 			return (NULL);
2754 		}
2755 		result[i++] = pool_elem_comp(pe);
2756 	}
2757 	(void) pool_rs_close(rs);
2758 	return (result);
2759 }
2760 
2761 /*
2762  * pool_version() returns the version of this library, depending on the supplied
2763  * parameter.
2764  *
2765  * Returns: library version depening on the supplied ver parameter.
2766  */
2767 uint_t
2768 pool_version(uint_t ver)
2769 {
2770 	switch (ver) {
2771 	case POOL_VER_NONE:
2772 		break;
2773 	case POOL_VER_CURRENT:
2774 		pool_workver = ver;
2775 		break;
2776 	default:
2777 		return (POOL_VER_NONE);
2778 	}
2779 	return (pool_workver);
2780 }
2781 
2782 /*
2783  * pool_associate() associates the supplied resource to the supplied pool.
2784  *
2785  * Returns: PO_SUCCESS/PO_FAIL
2786  */
2787 int
2788 pool_associate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2789 {
2790 	if (pool_conf_check(conf) != PO_SUCCESS)
2791 		return (PO_FAIL);
2792 
2793 	return (pool->pp_associate(pool, res));
2794 }
2795 
2796 /*
2797  * pool_dissociate() dissociates the supplied resource from the supplied pool.
2798  *
2799  * Returns: PO_SUCCESS/PO_FAIL
2800  */
2801 int
2802 pool_dissociate(pool_conf_t *conf, pool_t *pool, const pool_resource_t *res)
2803 {
2804 	if (pool_conf_check(conf) != PO_SUCCESS)
2805 		return (PO_FAIL);
2806 
2807 	if (elem_is_default(TO_ELEM(res)))
2808 		return (PO_SUCCESS);
2809 	return (pool->pp_dissociate(pool, res));
2810 }
2811 
2812 /*
2813  * Compare two elements for purposes of ordering.
2814  * Return:
2815  *	< 0 if e1 is "before" e2
2816  *	0 if e1 "equals" e2
2817  *	> 0 if e1 comes after e2
2818  */
2819 int
2820 pool_elem_compare_name(const pool_elem_t *e1, const pool_elem_t *e2)
2821 {
2822 	char *name1, *name2;
2823 	pool_value_t val = POOL_VALUE_INITIALIZER;
2824 	int retval;
2825 
2826 	/*
2827 	 * We may be asked to compare two elements from different classes.
2828 	 * They are different so return (1).
2829 	 */
2830 	if (pool_elem_same_class(e1, e2) != PO_TRUE)
2831 		return (1);
2832 
2833 	/*
2834 	 * If the class is PEC_SYSTEM, always match them
2835 	 */
2836 	if (pool_elem_class(e1) == PEC_SYSTEM)
2837 		return (0);
2838 
2839 	/*
2840 	 * If we are going to compare components, then use sys_id
2841 	 */
2842 	if (pool_elem_class(e1) == PEC_COMP) {
2843 		int64_t sys_id1, sys_id2;
2844 
2845 		if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2846 			return (-1);
2847 		}
2848 		(void) pool_value_get_int64(&val, &sys_id1);
2849 		if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2850 			return (-1);
2851 		}
2852 		(void) pool_value_get_int64(&val, &sys_id2);
2853 		retval = (sys_id1 - sys_id2);
2854 	} else {
2855 		if (pool_get_ns_property(e1, "name", &val) == POC_INVAL) {
2856 			return (-1);
2857 		}
2858 		(void) pool_value_get_string(&val, (const char **)&name1);
2859 		if ((name1 = strdup(name1)) == NULL) {
2860 			return (-1);
2861 		}
2862 
2863 		if (pool_get_ns_property(e2, "name", &val) == POC_INVAL) {
2864 			return (-1);
2865 		}
2866 
2867 		(void) pool_value_get_string(&val, (const char **)&name2);
2868 		retval = strcmp(name1, name2);
2869 		free(name1);
2870 	}
2871 	return (retval);
2872 }
2873 
2874 /*
2875  * Compare two elements for purposes of ordering.
2876  * Return:
2877  *	< 0 if e1 is "before" e2
2878  *	0 if e1 "equals" e2
2879  *	> 0 if e1 comes after e2
2880  */
2881 int
2882 pool_elem_compare(const pool_elem_t *e1, const pool_elem_t *e2)
2883 {
2884 	pool_value_t val = POOL_VALUE_INITIALIZER;
2885 	int64_t sys_id1, sys_id2;
2886 
2887 	/*
2888 	 * We may be asked to compare two elements from different classes.
2889 	 * They are different so return the difference in their classes
2890 	 */
2891 	if (pool_elem_same_class(e1, e2) != PO_TRUE)
2892 		return (1);
2893 
2894 	/*
2895 	 * If the class is PEC_SYSTEM, always match them
2896 	 */
2897 	if (pool_elem_class(e1) == PEC_SYSTEM)
2898 		return (0);
2899 
2900 	/*
2901 	 * Compare with sys_id
2902 	 */
2903 	if (pool_get_ns_property(e1, c_sys_prop, &val) == POC_INVAL) {
2904 		assert(!"no sys_id on e1\n");
2905 	}
2906 	(void) pool_value_get_int64(&val, &sys_id1);
2907 	if (pool_get_ns_property(e2, c_sys_prop, &val) == POC_INVAL) {
2908 		assert(!"no sys_id on e2\n");
2909 	}
2910 	(void) pool_value_get_int64(&val, &sys_id2);
2911 	return (sys_id1 - sys_id2);
2912 }
2913 
2914 /*
2915  * Return PO_TRUE if the supplied elems are of the same class.
2916  */
2917 int
2918 pool_elem_same_class(const pool_elem_t *e1, const pool_elem_t *e2)
2919 {
2920 	if (pool_elem_class(e1) != pool_elem_class(e2))
2921 		return (PO_FALSE);
2922 
2923 	/*
2924 	 * Check to make sure the fundamental class of the elements match
2925 	 */
2926 	if (pool_elem_class(e1) == PEC_RES_COMP ||
2927 	    pool_elem_class(e1) == PEC_RES_AGG)
2928 		if (pool_resource_elem_class(e1) !=
2929 		    pool_resource_elem_class(e2))
2930 			return (PO_FALSE);
2931 	if (pool_elem_class(e1) == PEC_COMP)
2932 		if (pool_component_elem_class(e1) !=
2933 		    pool_component_elem_class(e2))
2934 			return (PO_FALSE);
2935 	return (PO_TRUE);
2936 }
2937 
2938 /*
2939  * pool_conf_check() checks that the configuration state isn't invalid
2940  * and that the configuration was opened for modification.
2941  */
2942 int
2943 pool_conf_check(const pool_conf_t *conf)
2944 {
2945 	if (pool_conf_status(conf) == POF_INVALID) {
2946 		pool_seterror(POE_BADPARAM);
2947 		return (PO_FAIL);
2948 	}
2949 
2950 	if ((conf->pc_prov->pc_oflags & PO_RDWR) == 0) {
2951 		pool_seterror(POE_BADPARAM);
2952 		return (PO_FAIL);
2953 	}
2954 	return (PO_SUCCESS);
2955 }
2956