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