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