/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Portions Copyright 2005 Cyril Plisko */
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <langinfo.h>
#include <time.h>
#if !defined(DEBUG)
#else
#endif
#include <assert.h>
#include <dlfcn.h>
#include <synch.h>
#include <sys/systeminfo.h>
#include <libdevinfo.h>
#include <unistd.h>
#include <stdarg.h>
#include <limits.h>
#include <ftw.h>
#include <ctype.h>
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
/* Limit size of sysinfo return */
/*
* Attachment point specifier types.
*/
typedef enum {
static char *listopt_array[] = {
#define LISTOPT_CLASS 0
"class",
};
typedef struct {
} vers_req_t;
((v) <= CFGA_HSL_VERS))
/*
* Incomplete definition
*/
struct cfga_vers_ops;
/*
* Structure that contains plugin library information.
*/
typedef struct plugin_lib {
int (*cfga_ap_id_cmp_p)();
} plugin_lib_t;
typedef struct lib_cache {
char *lc_ap_id;
} lib_cache_t;
/*
* Library locator data struct - used to pass down through the device
* tree walking code.
*/
typedef struct lib_locator {
} lib_loc_t;
/*
* linked list of cfga_stat_data structs - used for
* config_list
*/
typedef struct stat_data_list {
/*
* linked list of arrays. Each array represents a bunch
* of list_data_t structures returned by a single call
* to a plugin's cfga_list_ext() routine.
*/
typedef struct array_list {
int nelem;
} array_list_t;
/*
* encapsulate config_list args to get them through the tree
* walking code
*/
typedef struct list_stat {
char **errstr;
} list_stat_t;
/*
* Internal operations for libcfgadm which are version dependant
*/
struct cfga_vers_ops {
};
/*
* Lock to protect list of libraries
*/
/*
* Forward declarations
*/
static const char *__config_strerror(cfga_err_t);
char **errstring);
static plugin_lib_t *lib_in_list(char *);
static void config_err(int, int, char **);
static void hold_lib(plugin_lib_t *);
static void rele_lib(plugin_lib_t *);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
char **errstring);
static void destroy_cache();
/*
* Plugin library search path helpers
*/
#if defined(__sparcv9)
#else
#endif
#if !defined(TEXT_DOMAIN)
#endif
/*
* Defined constants
*/
/*
* Error strings
*/
static char *
err_strings[] = {
NULL,
"Device library initialize failed",
"Memory allocation failed",
"Invalid argument(s)"
};
/*
* Table of version dependant routines
*/
};
/*
* Public interfaces for libcfgadm, as documented in config_admin.3x
*/
/*
* config_change_state
*/
int num_ap_ids,
char *const *ap_id,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
/*
* for each arg -
* load hs library,
* if force
* call cfga_state_change_func
* return status
* else
* call it's cfga_stat
* check condition
* call cfga_state_change_func
* return status
*/
int i;
/* Sanity checks */
if (state_change_cmd == CFGA_CMD_NONE)
return (retval);
if ((state_change_cmd < CFGA_CMD_NONE) ||
return (CFGA_INVAL);
}
!= CFGA_OK) {
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
/*
* operate on each ap_id
*/
CFGA_OK) {
break;
}
if ((flags & CFGA_FLAG_FORCE) ||
(state_change_cmd == CFGA_CMD_UNLOAD) ||
(state_change_cmd == CFGA_CMD_DISCONNECT) ||
(state_change_cmd == CFGA_CMD_UNCONFIGURE)) {
errno = 0;
} else {
/*
* Need to check condition before proceeding in
* the "configure direction"
*/
break;
}
errno = 0;
retval =
(*libp->cfga_change_state_p)(
flags);
} else {
}
}
}
return (retval);
}
/*
* config_private_func
*/
const char *function,
int num_ap_ids,
char *const *ap_ids,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
int i;
}
!= CFGA_OK) {
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
/*
* operate on each ap_id
*/
CFGA_OK) {
return (retval);
}
errno = 0;
flags);
}
return (retval);
}
/*
* config_test
*/
int num_ap_ids,
char *const *ap_ids,
const char *options,
char **errstring,
{
int i;
}
!= CFGA_OK) {
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
/*
* operate on each ap_id
*/
CFGA_OK) {
return (retval);
}
errno = 0;
}
return (retval);
}
int num_ap_ids,
char *const *ap_ids,
struct cfga_stat_data *buf,
const char *options,
char **errstring)
{
int nstat, n, i;
return (CFGA_ERROR);
}
/*
* V1 entry points don't support dynamic attachment points
*/
for (i = 0; i < num_ap_ids; i++) {
return (CFGA_APID_NOEXIST);
}
}
nstat = n = 0;
/*
* This is a V1 interface which can use only V1 plugins
*/
}
return (rc);
}
/*
* config_list
*/
struct cfga_stat_data **ap_id_list,
int *nlistp,
const char *options,
char **errstring)
{
int nstat;
}
nstat = 0;
/*
* This is a V1 interface which can use only V1 plugins
*/
*ap_id_list = NULL;
*nlistp = 0;
/*
* V1 interfaces don't support prefiltering, no class
* specified.
*/
}
return (CFGA_NOTSUPP);
} else {
return (retval);
}
}
/*
* config_list_ext
*/
int num_ap_ids,
char *const *ap_ids,
struct cfga_list_data **ap_id_list,
int *nlistp,
const char *options,
const char *listopts,
char **errstring,
{
char *class;
*nlistp = 0;
*ap_id_list = NULL;
}
return (CFGA_ERROR);
}
!= CFGA_OK) {
return (rc);
}
nstat = 0;
/*
* We support both V1 and V2 plugins through this entry
* point.
*/
list = 0;
/*
* discover and stat all attachment points
*/
list = 1;
/*
* Stat specified attachment points. With dynamic expansion
* more data may be returned than was specified by user.
*/
} else {
rc = CFGA_ERROR;
}
return (rc);
}
/*
* For the list command notify user if no attachment
* point is found in the system.
*
*/
/*
* If attachment points are being prefiltered, absence of data
* does not imply that config. admin. is not
* supported by the system.
*/
if (prefilter) {
/*
* Prefiltering: requested class is absent
*/
return (CFGA_APID_NOEXIST);
} else {
/*
* No attachment points in system
*/
return (CFGA_NOTSUPP);
}
} else {
return (rc);
}
}
/*
* config_unload_libs
*
* Attempts to remove all libs on the plugin list.
*/
void
{
/* destroy cache entries to remove refcnt agains plugins */
(void) mutex_lock(&plugin_list_lock);
continue;
}
}
(void) mutex_unlock(&plugin_list_lock);
}
/*
* config_ap_id_cmp
*/
int
const cfga_ap_log_id_t ap1,
const cfga_ap_log_id_t ap2)
{
int ret;
/*
* Extract static ap_ids
*/
if (sep1)
*sep1 = '\0';
if (sep2)
*sep2 = '\0';
/*
* Use the default comparator for static ap_ids
*/
if (ret)
return (ret);
/*
* static components match. They belong to
* the same static ap_id. Check if both are dynamic
* If not, static < dynamic.
*/
/*
* If both are static, then ap1 = ap2
*/
return (0);
/*
* Both are dynamic and belong to same static ap_id.
* Use the plugin comparator
*/
}
return (ret);
}
/*
* config_strerror
*/
const char *
{
return (NULL);
}
/*
* config_help
*/
int num_ap_ids,
char *const *ap_ids,
const char *options,
{
int i;
!= CFGA_OK) {
return (CFGA_ERROR);
}
if (num_ap_ids < 0) {
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
/*
* operate on each ap_id
*/
return (retval);
}
errno = 0;
}
return (retval);
}
/*
* Private support routines for the public interfaces
*/
static const char *
{
switch (cfgerrnum) {
case CFGA_OK:
ep = "Configuration operation succeeded";
break;
case CFGA_NACK:
ep = "Configuration operation cancelled";
break;
case CFGA_INVAL:
ep = "Configuration operation invalid";
break;
case CFGA_NOTSUPP:
ep = "Configuration administration not supported";
break;
case CFGA_OPNOTSUPP:
ep = "Configuration operation not supported";
break;
case CFGA_PRIV:
ep = "Insufficient privileges";
break;
case CFGA_BUSY:
ep = "Component system is busy, try again";
break;
case CFGA_SYSTEM_BUSY:
ep = "System is busy, try again";
break;
case CFGA_DATA_ERROR:
ep = "Data error";
break;
case CFGA_LIB_ERROR:
ep = "Library error";
break;
case CFGA_NO_LIB:
ep = "No Library found";
break;
ep = "Insufficient condition";
break;
case CFGA_ERROR:
ep = "Hardware specific failure";
break;
case CFGA_APID_NOEXIST:
ep = "Attachment point not found";
break;
case CFGA_ATTR_INVAL:
ep = "No attachment point with specified attributes found";
break;
default:
break;
}
return (ep);
}
/*
* listopts is a string in the getsubopt(3C) style:
* name1=value1,name2=value2,
*/
static cfga_err_t
{
/*
* NULL is a legal value for listopts
*/
return (CFGA_OK);
}
== NULL) {
return (CFGA_LIB_ERROR);
}
while (*optp != '\0') {
case LISTOPT_CLASS:
rc = CFGA_ERROR;
goto out;
}
rc = CFGA_LIB_ERROR;
goto out;
}
break;
default:
rc = CFGA_ERROR;
goto out;
}
}
/*FALLTHRU*/
out:
}
return (rc);
}
/*ARGSUSED*/
static cfga_err_t
{
return (CFGA_OK);
}
static cfga_err_t
{
return (CFGA_LIB_ERROR);
}
}
/*
* Obtain the devlink from a /devices path
*/
static int
{
return (DI_WALK_TERMINATE);
}
static cfga_err_t
{
return (CFGA_LIB_ERROR);
}
/* open devlink database */
return (CFGA_LIB_ERROR);
}
(void) di_devlink_fini(&hdl);
return (CFGA_OK);
}
/*
* mklog_common - make a logical name from the driver and instance
*/
static cfga_err_t
{
int inst;
errno = 0;
return (CFGA_OK);
}
return (CFGA_LIB_ERROR);
}
/*
* mklog_common - make a logical name from the driver and instance
*/
/*ARGSUSED*/
static cfga_err_t
{
int inst;
errno = 0;
return (CFGA_OK);
}
return (CFGA_LIB_ERROR);
}
/*
* resolve_lib_ref - relocate to use plugin lib
*/
static cfga_err_t
{
void *sym;
int plug_vers;
/*
* Version symbol not defined, must be the first version
*/
} else {
}
/*
* Check if plugin version matches request.
*/
return (CFGA_NO_LIB);
}
/*
* Record the plugin version and setup version dependant routines
*/
/* resolve symbols common to all versions */
perror("dlsym: cfga_change_state");
return (CFGA_LIB_ERROR);
} else
const char *, const char *, struct cfga_confirm *,
perror("dlsym: cfga_private_func");
return (CFGA_LIB_ERROR);
} else
const char *, const char *, struct cfga_confirm *,
perror("dlsym: cfga_test");
return (CFGA_LIB_ERROR);
} else
perror("dlsym: cfga_help");
return (CFGA_LIB_ERROR);
} else
const char *, cfga_flags_t))sym;
} else
libp->cfga_ap_id_cmp_p = (int (*)(const
/* Resolve version specific symbols */
}
/*ARGSUSED*/
static cfga_err_t
{
return (CFGA_OK);
}
static cfga_err_t
{
return (CFGA_NO_LIB);
}
perror("dlsym: cfga_stat");
return (CFGA_LIB_ERROR);
} else
struct cfga_stat_data *, const char *,
char **))sym;
perror("dlsym: cfga_list");
return (CFGA_LIB_ERROR);
} else
int *, const char *, char **))sym;
return (CFGA_OK);
}
static cfga_err_t
{
void *sym;
return (CFGA_NO_LIB);
}
perror("dlsym: cfga_list_ext");
return (CFGA_LIB_ERROR);
} else {
struct cfga_list_data **, int *, const char *,
const char *, char **, cfga_flags_t))sym;
return (CFGA_OK);
}
}
/*
* config_calloc_check - perform allocation, check result and
* set error string
*/
static void *
char **errstring)
{
void *p;
if (p == NULL) {
}
return (p);
}
/*
* config_get_lib - given an ap_id find the library name
* If successful, the plugin library is held.
*/
static cfga_err_t
const char *ap_id,
char **errstring)
{
char *apdup;
return (ret);
}
== NULL) {
return (CFGA_LIB_ERROR);
}
/*
* Separate into base and dynamic components
*/
goto out;
}
/*
* No upper limit on version
*/
/*
* We need atleast version 2 of the plug-in library
* interface since the ap_id has a dynamic component.
*/
} else {
}
/*
* If the ap_id is a devlink in CFGA_DEV_DIR, follow link
* to get the physical ap_id.
*/
}
!= NULL) {
"%s", path);
} else {
"%s", apdup);
}
/*
* find and load the library
* The base component of the ap_id is used to locate the plug-in
*
* dev links created for now.
*/
/*
* physical ap_id: Use ap_base as root for tree walk
* A link based apid (logical) will resolve to a physical
* ap_id.
*/
} else if ((type == LOGICAL_DRV_AP) ||
/*
* logical ap_id or ap_type: Use "/" as root for tree walk
* Note: an aptype cannot have a dynamic component
*/
} else {
}
#ifndef NDEBUG
/*
* variables used by assert() only which is disabled
* by defining NDEBUG (see top of this file)
*/
#endif /* NDEBUG */
/*
* If a dynamic component was present, v1 plug-ins are not
* acceptable.
*/
/*
* ap_physical is passed to plugins as their ap_id argument.
* Append dynamic component if any.
*/
sizeof (lib_loc_p->ap_physical));
}
/* cleanup */
/*FALLTHRU*/
out:
}
return (ret);
}
/* load_lib - load library for non-SHP attachment point node */
static cfga_err_t
{
}
/* load_lib_hp - load library for SHP attachment point node */
static cfga_err_t
{
}
/*
* load_lib_impl - Given a library pathname, create a entry for it
* in the library list, * if one does not already exist, and read
* lock it to keep it there.
*/
static cfga_err_t
{
char *devfs_path;
char *name;
return (CFGA_LIB_ERROR);
if (minor != DI_MINOR_NIL)
else
/*
* lock the library list
*/
(void) mutex_lock(&plugin_list_lock);
/*
* see if lib exist in list, if not, allocate a new one
*/
(void) mutex_unlock(&plugin_list_lock);
/* fill in logical and physical name in libloc_p */
if (minor != DI_MINOR_NIL) {
!= CFGA_OK) {
return (CFGA_LIB_ERROR);
}
} else {
return (CFGA_LIB_ERROR);
}
}
return (CFGA_OK);
}
/* allocate a new plugin_lib_t structure */
(void) mutex_unlock(&plugin_list_lock);
return (CFGA_LIB_ERROR);
}
/*
* ensure that the lib is open and linked in
*/
(void) mutex_unlock(&plugin_list_lock);
return (CFGA_NO_LIB);
}
if (minor != DI_MINOR_NIL) {
!= CFGA_OK) {
(void) mutex_unlock(&plugin_list_lock);
return (CFGA_NO_LIB);
}
} else {
(void) mutex_unlock(&plugin_list_lock);
return (CFGA_NO_LIB);
}
}
/*
* link in new entry to the end of list
*/
list_libp = &plugin_list;
/* Initialize refcnt to 1 */
(void) mutex_unlock(&plugin_list_lock);
/*
* record libp and physical node name in the libloc struct
*/
return (CFGA_OK);
}
/*
* find_lib - find library for non-SHP attachment point node
*/
static cfga_err_t
{
int i;
/* Make sure pathname and class is null if we fail */
/*
* Initialize possible library tags.
*/
return (CFGA_LIB_ERROR);
}
i = 0;
/*
* Cycle through the array of names to find the library.
*/
for (i = 0; i < NUM_LIB_NAMES; i++) {
/* Attachment points may not have a class (i.e. are generic) */
if (name[i][0] == '\0') {
continue;
}
goto found;
}
return (CFGA_NO_LIB);
/* Record class name (if any) */
class);
return (CFGA_OK);
}
/*
* find_lib_hp - find library for SHP attachment point
*/
/*ARGSUSED*/
static cfga_err_t
{
/* Make sure pathname and class is null if we fail */
/*
* Initialize possible library tags.
*
* Only support PCI class for now, this will need to be
* changed as other plugins are migrated to SHP plugin.
*/
class = "pci";
#if 0
/*
* No type check for now as PCI is the only class SHP plugin
* supports. In the future we'll need to enable the type check
* and set class accordingly, when non PCI plugins are migrated
* to SHP. In that case we'll probably need to add an additional
* interface between libcfgadm and the plugins, and SHP plugin will
* implement this interface which will translate the bus specific
* strings to standard classes that libcfgadm can recognize, for
* PCIE_NATIVE_HP_TYPE to string "pci". We'll also need to bump up
* SHP plugin version to 3 to use the new interface.
*/
class = "pci";
} else {
goto fail;
}
#endif
goto found;
fail:
return (CFGA_NO_LIB);
/* Record class name (if any) */
class);
return (CFGA_OK);
}
/*
* find_lib_impl - Given an attachment point node find it's library
*/
static cfga_err_t
char *name,
{
/*
* Initialize machine name and arch name
*/
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
}
/*
* Try path based upon platform name
*/
/* file exists, is it a lib */
goto found;
}
}
/*
* Try path based upon machine name
*/
/* file exists, is it a lib */
goto found;
}
}
/*
* Try path based upon arch name
*/
/* file exists, is it a lib */
goto found;
}
}
/*
* Try generic location
*/
/* file exists, is it a lib */
goto found;
}
}
return (CFGA_NO_LIB);
/* we got one! */
lib);
return (CFGA_OK);
}
static cfga_err_t
{
(void) mutex_lock(&lib_cache_lock);
while (entry) {
(void) mutex_unlock(&lib_cache_lock);
return (CFGA_OK);
}
}
(void) mutex_unlock(&lib_cache_lock);
return (CFGA_ERROR);
}
static void
{
return;
return;
}
(void) mutex_lock(&lib_cache_lock);
(void) mutex_unlock(&lib_cache_lock);
}
static void
{
(void) mutex_lock(&lib_cache_lock);
while (entry) {
}
(void) mutex_unlock(&lib_cache_lock);
}
/*
* find_ap_common - locate a particular attachment point
*/
static cfga_err_t
const char *physpath,
char **errstring)
{
return (CFGA_OK);
return (CFGA_LIB_ERROR);
}
/* Remove devices prefix (if any) */
}
/* Remove dynamic component if any */
*cp = '\0';
}
/* Remove minor name (if any) */
*cp = '\0';
}
/*
* begin walk of device tree
*
* of the new framework, we should first match with hp nodes. If
* find it here.
*/
if (rnode)
else
wnode = DI_NODE_NIL;
if (wnode == DI_NODE_NIL) {
if (rnode == DI_NODE_NIL) {
return (CFGA_LIB_ERROR);
} else {
/*
* di_lookup_node() may fail, either because the
* ap_id does not exist, or because the ap_id refers
* to a legacy PCI slot, thus we'll not able to
* find node using DINFOHP, try to see if we can
* find one using DINFOCACHE.
*/
goto find_minor;
}
}
/*
* Failed to find a matching hp node, try minor node.
*/
if (rnode)
else
wnode = DI_NODE_NIL;
if (wnode == DI_NODE_NIL) {
if (rnode == DI_NODE_NIL) {
return (CFGA_LIB_ERROR);
} else {
/*
* di_lookup_node() may fail, because the
* ap_id does not exist.
*/
return (CFGA_APID_NOEXIST);
}
}
}
return (CFGA_OK);
} else {
}
}
/*
* check_ap - called for each non-SHP attachment point found
*/
static int
void *arg)
{
}
/*
* check_ap_hp - called for each SHP attachment point found
*/
static int
void *arg)
{
}
/*
* check_ap_impl - called for each attachment point found
*
* This is used in cases where a particular attachment point
* or type of attachment point is specified via a logical name or ap_type.
* Not used for physical names or in the list case with no
* ap's specified.
*/
static int
void *arg)
{
char *node_minor;
char *drv_name;
int comparison_test;
int instance;
return (DI_WALK_CONTINUE);
/*
* This routime handles only aptypes and driver based logical apids.
*/
if (type == LOGICAL_DRV_AP) {
*cp = '\0';
cp--;
cp--;
cp++;
*cp = '\0';
return (DI_WALK_CONTINUE);
}
if (minor != DI_MINOR_NIL)
else
return (DI_WALK_CONTINUE);
}
/*
* If the base matches driver and instance try and find a lib for it,
* then load it. On any failure we continue the walk.
*
* driver based logical ap_ids are derived from driver name + instance.
* Ap_types are just partial driver names.
*
*/
comparison_test = 0;
comparison_test = 1;
}
} else {
comparison_test = 1;
}
}
if (comparison_test) {
/*
* save the correct type of error so user does not get confused
*/
if (minor != DI_MINOR_NIL) {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
} else {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
}
return (DI_WALK_TERMINATE);
} else {
return (DI_WALK_CONTINUE);
}
}
/*
* check_ap_phys - called for each non-SHP attachment point found
*/
static int
void *arg)
{
}
/*
* check_ap_phys_hp - called for each SHP attachment point found
*/
static int
void *arg)
{
}
/*
* check_ap_phys_impl - called for each attachment point found
*
* This is used in cases where a particular attachment point
* is specified via a physical name. If the name matches then
* we try and find and load the library for it.
*/
static int
void *arg)
{
char *devfs_path;
char *minor_name;
return (DI_WALK_CONTINUE);
if (minor != DI_MINOR_NIL)
else
return (DI_WALK_CONTINUE);
}
if (minor != DI_MINOR_NIL) {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
} else {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
}
return (DI_WALK_TERMINATE);
} else {
return (DI_WALK_CONTINUE);
}
}
/*
* lib_in_list
*
* See if library, as specified by the full pathname and controller
* instance number is already represented in the plugin library list.
* If the instance number is -1 it is ignored.
*/
static plugin_lib_t *
{
return (libp);
}
}
return (NULL);
}
/*
* Coalesce stat and list data into single array
*/
static cfga_err_t
int *nlistp,
{
int i, j;
*ap_id_list = NULL;
*nlistp = 0;
return (CFGA_OK);
}
/*
* allocate the array
*/
rc = CFGA_LIB_ERROR;
goto out;
}
/*
* copy all the stat elements (if any) into the array
*/
rc = CFGA_LIB_ERROR;
goto out;
}
}
/*
* copy all the list elements (if any) into the array
*/
rc = CFGA_LIB_ERROR;
goto out;
}
}
}
rc = CFGA_LIB_ERROR;
} else {
}
/*FALLTHRU*/
out:
/* clean up */
*ap_id_list = cldp;
} else {
*ap_id_list = NULL;
*nlistp = 0;
}
return (rc);
}
/*
* The caller of this routine may supply a buffer through
* ap_id_list for returning data. Otherwise, this routine allocates the
* buffer.
*/
static cfga_err_t
{
int i;
*nlistp = 0;
return (CFGA_OK);
}
/*
* allocate the array if caller does not supply one.
*/
if (*ap_id_list == NULL) {
rc = CFGA_LIB_ERROR;
goto out;
}
} else {
buf = *ap_id_list;
}
/*
* copy the stat elements into the array
*/
rc = CFGA_LIB_ERROR;
goto out;
}
}
out:
*ap_id_list = buf;
} else {
/*
* Free buffer only if we allocated it.
*/
if (*ap_id_list == NULL) {
}
*nlistp = 0;
}
return (rc);
}
/*
* list_common - walk the device tree and stat all attachment points.
*/
static cfga_err_t
{
/*
* May walk a subset of all attachment points in the device tree if
* a class is specified
*/
l_sep = ":";
} else {
}
/*
* Walk all hp nodes
*/
return (CFGA_LIB_ERROR);
}
/* No need to filter on class for now */
/*
* Walk all minor nodes
*/
return (CFGA_LIB_ERROR);
}
}
return (CFGA_OK);
}
static void
{
int len = 0;
/*
* If errstring is null it means user in not interested in getting
* error status. So we don't do all the work
*/
return;
}
if (errnum != 0) {
syserr = syserr_num;
}
} else
}
if (p == NULL) {
return;
}
(void) strcpy(p, q);
}
*errstring = p;
}
/*
* do_list_common - list non-SHP attachment point
*/
static int
void *arg)
{
char *minor_name;
/*
* created for now, we need to specifically exclude these connectors
* during walking minor nodes.
*/
== DI_NODE_NIL) {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
}
}
/*
* do_list_common_hp - list SHP attachment point
*/
static int
void *arg)
{
}
/*
* do_list_common_impl - Routine to list attachment point as part of
* a config_list opertion. Used by both v1 and v2 interfaces.
* This is somewhat similar to config_get_lib() and its helper routines
* except that the ap_ids are always physical and don't have dynamic
* components.
*/
static int
void *arg)
{
return (DI_WALK_CONTINUE);
/*
* try and find a lib for this node
*/
if (minor != DI_MINOR_NIL) {
} else {
}
return (DI_WALK_CONTINUE);
}
/*
* Load all plugins. We will check compatibility later in this
* routine.
*/
if (minor != DI_MINOR_NIL) {
} else {
}
return (DI_WALK_CONTINUE);
}
/*
* Note: For list type routines (list all attachment points in
* device tree) we don't pass errstring to the plugin, nor do we
* stop the walk if an error occurs in the plugin.
*/
if (minor != DI_MINOR_NIL) {
} else {
/*
* If the underlying hotplug daemon is not enabled,
* the SHP attach points will not be shown, this
* could confuse the uesrs. We specifically pass the
* errstring to SHP plugin so that it can set the
* errstring accordingly in this case, giving users
* a hint.
*/
lstatp->shp_errstr =
}
}
}
}
}
return (DI_WALK_CONTINUE);
}
/*
* stat_common - stat a user specified set of attachment points.
*/
static cfga_err_t
int num_ap_ids,
char *const *ap_ids,
const char *class,
{
int i;
/*
* operate on each ap_id
*/
for (i = 0; i < num_ap_ids; i++) {
break;
}
/*
* do pre-filtering if requested
*/
continue;
}
/*
* Unlike list type routines, while stat'ing specific
* attachment points we pass errstring to the plugins
* and halt if an error occurs in the plugin.
*/
break;
}
}
}
return (rc);
}
/*ARGSUSED*/
static cfga_err_t
{
return (CFGA_OK);
}
/*
* Pass errstring as a separate argument. Some higher level routines need
* it to be NULL.
*/
static cfga_err_t
{
/*
* allocate stat data buffer and list element
*/
return (CFGA_LIB_ERROR);
}
/*
* Do the stat
*/
errno = 0;
return (rc);
}
/*
* Set up the logical and physical id's.
* For v1 interfaces, the generic library (libcfgadm) creates the
* ap_ids. mklog() is assumed to have been called in
* the caller of this routine.
*/
/*
* link it in
*/
} else {
}
/* keep count */
return (CFGA_OK);
}
static cfga_err_t
{
int i;
char *class;
/*
* allocate array list
*/
return (CFGA_LIB_ERROR);
}
/*
* The listopts argument is currently unused. Use NULL
*/
errno = 0;
return (rc);
}
/*
* Set up the logical and physical id's if necessary.
* For v2 interfaces, the generic library (libcfgadm) creates the
* ap_ids only if there are no dynamic attachment points and the
* plug-in does not create the name itself. mklog() is
* assumed to have been called in the caller of this routine.
*/
if (clog == '\0') {
}
if (cphys == '\0') {
}
}
} else {
}
/* Fill in the class information for all list elements */
}
/*
* link it in
*/
} else {
}
/* keep count */
return (CFGA_OK);
}
/*
* Check if a plugin version is within requested limits.
*/
static int
{
return (0);
}
return (0);
}
return (1);
}
/*
* find_arg_type - determine if an argument is an ap_id or an ap_type.
* Adapted from cfgadm.c
*/
static cfga_ap_types_t
{
/*
* sanity checks
*/
return (UNKNOWN_AP);
}
/*
* Extract the base component
*/
} else {
}
return (UNKNOWN_AP);
}
/* Copy only the first "len" chars */
/*
* If it starts with a slash and is stat-able its a physical.
*/
return (PHYSICAL_AP);
}
/*
* Is this a symlink in CFGA_DEV_DIR ?
*/
return (LOGICAL_LINK_AP);
}
/*
* Check for ":" which is always present in an ap_id
* but not in an ap_type.
* we need to check that the characters right before the : are digits
* since an ap_id is of the form <name><instance>:<specific ap name>
*/
} else {
digit = 0;
digit++;
break;
}
}
if (digit == 0) {
} else {
}
}
return (type);
}
/*ARGSUSED*/
static cfga_err_t
{
return (CFGA_OK);
}
static cfga_err_t
{
return (CFGA_LIB_ERROR);
}
errno = 0;
== CFGA_OK) {
} else {
}
return (rc);
}
static cfga_err_t
{
int nelem;
return (CFGA_LIB_ERROR);
}
errno = 0;
nelem = 0;
} else {
}
return (rc);
}
/* mask represents the flags accepted */
static cfga_err_t
{
return (CFGA_ERROR);
} else {
return (CFGA_OK);
}
}
static cfga_err_t
{
return (CFGA_ERROR);
} else {
return (CFGA_OK);
}
}
/*
* Returns the class or the empty string if attacment point has
* no class.
*/
static char *
{
char *cp, c;
if (minor == DI_MINOR_NIL) {
return (NULL);
}
return (NULL);
}
return (NULL);
}
c = *cp;
if (c != '\0' && c != ':') {
return (NULL);
}
if (c == ':') {
cp++;
}
return (cp);
}
/*
* Transform stat data to list data
*/
static void
{
statp->ap_phys_id);
}
static void
{
}
}
}
static cfga_err_t
{
char *cp;
return (CFGA_ERROR);
}
return (CFGA_OK);
}
*cp = '\0';
return (CFGA_LIB_ERROR);
}
return (CFGA_OK);
}
static void
{
dyncomp);
}
}
/*
* Default implementation of cfga_ap_id_cmp. Works for most cases
* except for long hex number sequences like world-wide-name.
*
* This function compares the ap's in a generic way. It does so by
* determining the place of difference between the 2 aps. If the first
* difference is a digit, it attempts to obtain the numbers and compare them
* Otherwise it just compares the aps as strings
*/
static int
{
int i = 0;
/*
* Search for first different char
*/
i++;
/*
* If one of the char is a digit, back up to where the
* number started, compare the number.
*/
i--;
}
/* One of them isn't a number, compare the char */
}
static void
{
}
static void
{
}