config_admin.c revision 9595f109a086b122e563aa9b0a4ec2304944f3de
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <langinfo.h>
#include <time.h>
#if !defined(DEBUG)
#define NDEBUG 1
#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 */
#define SYSINFO_LENGTH 256
/*
* Attachment point specifier types.
*/
typedef enum {
static char *listopt_array[] = {
#define LISTOPT_CLASS 0
"class",
};
typedef struct {
int v_min; /* Min acceptable version */
int v_max; /* Max acceptable version */
} vers_req_t;
#define INVALID_VERSION -1
#define VALID_HSL_VERS(v) (((v) >= CFGA_HSL_V1) && \
((v) <= CFGA_HSL_VERS))
/*
* Incomplete definition
*/
struct cfga_vers_ops;
/*
* Structure that contains plugin library information.
*/
typedef struct plugin_lib {
int refcnt; /* reference count */
void *handle; /* handle from dlopen */
cfga_err_t (*cfga_test_p)();
cfga_err_t (*cfga_stat_p)();
cfga_err_t (*cfga_list_p)();
cfga_err_t (*cfga_help_p)();
int (*cfga_ap_id_cmp_p)();
int plugin_vers; /* actual plugin version */
} plugin_lib_t;
static plugin_lib_t plugin_list;
typedef struct lib_cache {
char *lc_ap_id;
char *lc_ap_physical; /* physical ap_id */
char *lc_ap_logical; /* logical ap_id */
} lib_cache_t;
static lib_cache_t *lib_cache;
static mutex_t lib_cache_lock;
/*
* Library locator data struct - used to pass down through the device
* tree walking code.
*/
typedef struct lib_locator {
char ap_base[MAXPATHLEN];
char ap_logical[CFGA_LOG_EXT_LEN];
char ap_physical[CFGA_PHYS_EXT_LEN];
char ap_class[CFGA_CLASS_LEN];
char pathname[MAXPATHLEN];
} lib_loc_t;
/*
* linked list of cfga_stat_data structs - used for
* config_list
*/
typedef struct stat_data_list {
struct stat_data_list *next;
/*
* 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 {
struct array_list *next;
int nelem;
} array_list_t;
/*
* encapsulate config_list args to get them through the tree
* walking code
*/
typedef struct list_stat {
const char *opts; /* Hardware specific options */
char **errstr;
int *countp; /* Total number of list and stat structures */
} list_stat_t;
/*
* Internal operations for libcfgadm which are version dependant
*/
struct cfga_vers_ops {
};
/*
* Lock to protect list of libraries
*/
static mutex_t plugin_list_lock;
/*
* Forward declarations
*/
static const char *__config_strerror(cfga_err_t);
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
*/
#define LIB_PATH_BASE1 "/usr/platform/"
#define LIB_PATH_BASE2 "/usr"
#if defined(__sparcv9)
#define LIB_PATH_MIDDLE "/lib/cfgadm/sparcv9/"
#define LIB_PATH_MIDDLE "/lib/cfgadm/amd64/"
#else
#define LIB_PATH_MIDDLE "/lib/cfgadm/"
#endif
#define LIB_PATH_TAIL ".so.1"
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
/*
* Defined constants
*/
#define DEVICES_DIR "/devices"
#define DOT_DOT_DEVICES "../devices"
#define CFGA_DEV_DIR "/dev/cfg"
#define SLASH "/"
#define CFGA_NO_CLASS "none"
/*
* Error strings
*/
#define DI_INIT_FAILED 1
#define ALLOC_FAILED 2
#define INVALID_ARGS 3
static char *
err_strings[] = {
NULL,
"Device library initialize failed",
"Memory allocation failed",
"Invalid argument(s)"
};
static const char err_sep[] = ": ";
/*
* 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;
char apstat1[CFGA_PHYS_EXT_LEN];
char apstat2[CFGA_PHYS_EXT_LEN];
/*
* 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;
char *drv, *minor_name;
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
*/
/*
* 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 - 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;
/*
* 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 */
!= CFGA_OK) {
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);
}
(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);
}
#define NUM_LIB_NAMES 2
/*
* find_lib - Given an attachment point node find it's library
*
*/
static cfga_err_t
{
char lib[MAXPATHLEN];
static char plat_name[SYSINFO_LENGTH];
static char machine_name[SYSINFO_LENGTH];
static char arch_name[SYSINFO_LENGTH];
int i = 0;
/* Make sure pathname and class is null if we fail */
/*
* Initialize machine name and arch name
*/
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
return (CFGA_ERROR);
}
}
/*
* 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;
}
/*
* Try path based upon platform name
*/
name[i], LIB_PATH_TAIL);
/* file exists, is it a lib */
goto found;
}
}
/*
* Try path based upon machine name
*/
name[i], LIB_PATH_TAIL);
/* file exists, is it a lib */
goto found;
}
}
/*
* Try path based upon arch name
*/
name[i], LIB_PATH_TAIL);
/* 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);
/* Record class name (if any) */
class);
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
*/
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 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 aptype[MAXPATHLEN];
char *node_minor;
char *drv_name;
char inst[MAXPATHLEN];
char inst2[MAXPATHLEN];
int comparison_test;
int instance;
/*
* 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);
}
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
*/
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
return (DI_WALK_TERMINATE);
} else {
return (DI_WALK_CONTINUE);
}
}
/*
* check_ap_phys - 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 phys_name[MAXPATHLEN];
char *devfs_path;
char *minor_name;
return (DI_WALK_CONTINUE);
}
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 *
lib_in_list(char *libpath)
{
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
{
char nodetype[MAXPATHLEN];
/*
* begin walk of device tree
*/
return (CFGA_LIB_ERROR);
}
/*
* May walk a subset of all attachment points in the device tree if
* a class is specified
*/
l_sep = ":";
} else {
}
return (CFGA_OK);
}
static void
{
char syserr_num[20];
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 - 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)
{
/*
* try and find a lib for this node
*/
return (DI_WALK_CONTINUE);
}
/*
* Load all plugins. We will check compatibility later in this
* routine.
*/
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.
*/
}
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
find_arg_type(const char *ap_id)
{
/*
* 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
{
}