/*
* 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
*/
/*
*/
#ifdef lint
#endif
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stropts.h>
#include <time.h>
#include <dirent.h>
#ifdef __sparc
#endif /* __sparc */
#include "libdevinfo.h"
#include "device_info.h"
#include <regex.h>
#include <paths.h>
(ch) == '-')
/*
* Macros to produce a quoted string containing the value of a
* preprocessor macro. For example, if SIZE is defined to be 256,
* VAL2STR(SIZE) is "256". This is used to construct format
* strings for scanf-family functions below.
*/
#define QUOTE(x) #x
typedef enum {
typedef enum {
} token_t;
typedef enum {
} conf_state_t;
/* structure to hold entries with mpxio-disable property in driver.conf file */
struct conf_entry {
char *name;
char *parent;
char *class;
char *unit_address;
int port;
int mpxio_disable;
};
struct conf_file {
char *filename;
int linenum;
};
/* #define DEBUG */
#ifdef DEBUG
int devfsmap_debug = 0;
static void vlog_debug_msg(char *, va_list);
static void log_debug_msg(char *, ...);
#ifdef __sparc
static void log_confent_list(char *, struct conf_entry *, int);
static void log_pathlist(char **);
#endif /* __sparc */
#else /* DEBUG */
#endif /* DEBUG */
/*
* Leave NEWLINE as the next character.
*/
static void
{
int ch;
break;
}
}
}
/* ignore parsing errors */
/*ARGSUSED*/
static void
{
#ifdef DEBUG
log_debug_msg("WARNING: %s line # %d: ",
#endif /* DEBUG */
}
/* return the next token from the given driver.conf file, or -1 on error */
static token_t
{
char *cp;
if (size < 2)
return (-1);
;
switch (ch) {
case '=':
break;
case '&':
token = T_AMPERSAND;
break;
case '|':
break;
case '*':
break;
case '#':
break;
case ':':
break;
case ';':
token = T_SEMICOLON;
break;
case ',':
break;
case '/':
break;
case ' ':
case '\t':
case '\f':
if (--remain == 0) {
*cp = '\0';
return (-1);
}
}
break;
case '\n':
case '\r':
break;
case '"':
remain++;
cp--;
badquote = 0;
switch (ch) {
case '\n':
case EOF:
*cp++ = '\n';
badquote = 1;
break;
case '\\':
if (--remain == 0) {
*cp = '\0';
return (-1);
}
/* escape the character */
break;
}
oval = 0;
ch -= '0';
}
/* check for character overflow? */
if (oval > 127) {
"Character "
"overflow detected.\n");
}
break;
default:
if (--remain == 0) {
*cp = '\0';
return (-1);
}
break;
}
}
break;
case EOF:
break;
default:
/*
* detect a lone '-' (including at the end of a line), and
* identify it as a 'name'
*/
if (ch == '-') {
if (--remain == 0) {
*cp = '\0';
return (-1);
}
remain++;
cp--;
break;
}
if (--remain == 0) {
*cp = '\0';
return (-1);
}
}
if (ch == '0') {
if (--remain == 0) {
*cp = '\0';
return (-1);
}
if (--remain == 0) {
*cp = '\0';
return (-1);
}
}
} else {
goto digit;
}
} else {
if (--remain == 0) {
*cp = '\0';
return (-1);
}
}
}
if (ch != '\\') {
} else {
/*
* if the character was a backslash,
* back up so we can overwrite it with
* the next (i.e. escaped) character.
*/
remain++;
cp--;
}
if (ch == '\\')
if (--remain == 0) {
*cp = '\0';
return (-1);
}
}
} else {
return (-1);
}
break;
}
*cp = '\0';
return (token);
}
#ifdef __sparc
static void
{
if (confent->unit_address)
}
static void
{
}
}
/*
* Parse the next entry from the driver.conf file and return in the form of
* a pointer to the conf_entry.
*/
static struct conf_entry *
{
return (NULL);
do {
switch (token) {
case T_NAME:
switch (state) {
case prop_equals_string:
case prop_equals_integer:
case begin:
goto bad;
break;
default:
}
break;
case T_EQUALS:
switch (state) {
case prop:
state = prop_equals;
break;
default:
}
break;
case T_STRING:
switch (state) {
case prop_equals:
goto bad;
"'parent' property already specified\n");
goto bad;
}
"'name' property already specified\n");
goto bad;
}
"'class' property already specified\n");
goto bad;
}
== 0) {
if (confent->unit_address) {
"'unit-address' property already specified\n");
goto bad;
}
== 0) {
"'mpxio-disable' property already specified\n");
goto bad;
}
confent->mpxio_disable = 0;
else {
"'mpxio-disable' property setting is invalid. "
"The value must be either \"yes\" or \"no\"\n");
goto bad;
}
} else {
}
break;
case prop_equals_string_comma:
break;
default:
}
break;
case T_HEXVAL:
case T_DECVAL:
switch (state) {
case prop_equals:
"'port' property already specified\n");
goto bad;
}
} else
break;
break;
default:
}
break;
case T_COMMA:
switch (state) {
case prop_equals_string:
break;
case prop_equals_integer:
break;
default:
}
break;
case T_NEWLINE:
break;
case T_POUND:
break;
case T_EOF:
goto bad;
default:
goto bad;
}
failed = 0;
bad:
if (prop_name)
if (string)
if (failed == 1) {
return (NULL);
}
return (confent);
}
/*
* Parse all entries with mpxio-disable property in the given driver.conf
* file.
*
* fname driver.conf file name
* confent_list on return *confent_list will contain the list of
* driver.conf file entries with mpxio-disable property.
* mpxio_disable on return *mpxio_disable is set to the setting of the
* driver global mpxio-dissable property as follows.
* 0 if driver mpxio-disable="no"
* 1 if driver mpxio-disable="yes"
* -1 if driver mpxio-disable property isn't specified.
*/
static void
int *mpxio_disable)
{
*confent_list = NULL;
*mpxio_disable = -1;
return;
switch (token) {
case T_POUND:
/*
* Skip comments.
*/
break;
case T_NAME:
MAX_TOKEN_SIZE)) == NULL)
break;
/*
* No name indicates global property.
* Make sure parent and class not NULL.
*/
"missing name attribute\n");
if (*mpxio_disable == -1)
else
"'mpxio-disable' property already specified\n");
}
break;
}
/*
* This is a node spec, either parent or class
* must be specified.
*/
"missing parent or class attribute\n");
break;
}
/* only need entries with mpxio_disable property */
break;
}
if (tail)
else
*confent_list = confent;
break;
case T_NEWLINE:
break;
default:
break;
}
}
}
/*
* Return the driver class of the given driver_name.
* The memory for the driver class is allocated by this function and the
* caller must free it.
*/
static char *
{
logdmsg(("get_driver_class: rootdir = %s, driver name = %s\n",
rootdir, driver_name));
logdmsg(("get_driver_class: failed to open %s: %s\n",
return (NULL);
}
/* LINTED - unbounded string specifier */
logdmsg(("get_driver_class: driver class = %s\n",
class_name));
return (strdup(class_name));
}
}
return (NULL);
}
static int
{
char *par;
logdmsg(("lookup_in_confent_list: %s = \"%s\", unit_addr = \"%s\", "
if (unit_addr) {
return (confent->mpxio_disable);
} else {
return (confent->mpxio_disable);
}
}
return (-1);
}
/*
* lookup mpxio-disabled property setting for the given path in the given
* driver.conf file. Match the entries from most specific to least specific.
*
* conf_file the path name of either fp.conf, qlc.conf or scsi_vhci.conf
* path /devices node path without the /devices prefix.
* If the conf_file is fp.conf, path must be a fp node path
* if the conf_file is qlc.conf, path must be a qlc node path.
* if the conf_file is scsi_vhci.conf, path must be NULL.
* ex: /pci@8,600000/SUNW,qlc@4/fp@0,0
* /pci@8,600000/SUNW,qlc@4
*
* returns:
* 0 if mpxio-disable="no"
* 1 if mpxio-disable="yes"
* -1 if mpxio-disable property isn't specified.
*/
static int
{
int mpxio_disable;
logdmsg(("lookup_in_conf_file: rootdir = \"%s\", conf_file = \"%s\", "
#ifdef DEBUG
#endif
/* if path is NULL, return driver global mpxio-disable setting */
rv = mpxio_disable;
goto done;
}
goto done;
*node_name = '\0';
node_name++;
goto done;
*node_addr = '\0';
node_addr++;
/* get port number; encoded in the node addr as a hex number */
} else
/*
* Match from most specific to least specific;
* first, start the lookup based on full path.
*/
goto done;
/* lookup nodename@address */
goto done;
}
/* di_init() doesn't work when 0 is passed in flags */
if (par_node != DI_NODE_NIL) {
}
/* lookup bindingname@address */
par_node_addr != NULL) {
goto done;
}
/* lookup binding name */
if (par_binding_name != NULL) {
goto done;
}
if (par_driver_name != NULL) {
/* lookup driver name */
goto done;
/* finally, lookup class name */
if (par_driver_class != NULL) {
goto done;
}
}
/*
* no match so far;
* use the driver global mpxio-disable setting if exists.
*/
rv = mpxio_disable;
done:
if (par_driver_class != NULL)
if (confent_list != NULL)
if (par_node != DI_NODE_NIL)
return (rv);
}
/*
* Given client_name return whether it is a phci or vhci based name.
* client_name is /devices name of a client without the /devices prefix.
*
* client_name Return value
* other CLIENT_TYPE_UNKNOWN
*/
static client_type_t
{
sizeof (SLASH_SCSI_VHCI) - 1) == 0)
return (CLIENT_TYPE_VHCI);
if (*client_name != '/')
return (CLIENT_TYPE_UNKNOWN);
return (CLIENT_TYPE_UNKNOWN);
*p1 = '\0';
else
*p1 = '/';
return (client_type);
}
/*
* Compare controller name portion of dev1 and dev2.
*
* rootdir root directory of the target environment
* dev1 can be either a /dev link or /devices name in the target
* environemnt
* dev2 /devices name of a device without the /devices prefix
*
* Returns:
* 0 if controller names match
* 1 if controller names don't match
* -1 an error occurred.
*/
static int
{
int linksize;
char *p1, *p;
logdmsg(("compare_controller: rootdir = %s, dev1 = %s, dev2 = %s\n",
== 0) {
logdmsg(("compare_controller: physdev1 = %s\n",
physdev1));
} else
return (-1);
} else
return (-1);
/* strip the device portion */
return (-1);
*p = '\0';
return (-1);
*p = '\0';
logdmsg(("compare_controller: path1 = %s, path2 = %s\n",
*p = '/';
return (0);
} else {
*p = '/';
return (1);
}
}
/*
* Check if the specified device path is on the root controller.
*
* rootdir root directory of the target environment
* path /devices name of a device without the /devices prefix
*
* Returns
* 1 if the path is on the root controller
* 0 if the path is not on the root controller
* -1 if an error occurs
*/
static int
{
char *tmpfile;
path));
logdmsg(("is_root_controller: failed to open %s: %s\n",
return (-1);
}
logdmsg(("is_root_controller: getvfsfile: failed to read "
"vfstab entry for mount point \"/\": %s\n",
return (-1);
}
/* check if the root is an svm metadisk */
return (1);
else
return (0);
}
logdmsg(("is_root_controller: tempnam: failed: %s\n",
return (-1);
}
/* get metadisk components using metastat command */
rv = 1;
goto out;
}
}
rv = 0;
}
out:
if (fp)
return (rv);
}
static int
{
int x;
if (x == 0)
return (1);
else
return (0);
}
/*
* Check if mpxio is enabled or disabled on the specified device path.
* Looks through the .conf files to determine the mpxio setting.
*
* rootdir root directory of the target environment
* path /devices name of a device without the /devices prefix and
* minor name component.
*
* Returns
* 1 if mpxio is disabled
* 0 if mpxio is enabled
* -1 if an error occurs
*/
static int
{
int mpxio_disable;
char *p;
logdmsg(("is_mpxio_disabled: rootdir = %s, path = %s\n",
/*
* scsi_vhci.conf doesn't exist:
* if upgrading from a pre solaris 9 release. or
* if this function is called during fresh or flash install
* prior to installing scsi_vhci.conf file.
*/
/* upgrading from pre solaris 9 */
return (1);
else
/* fresh or flash install */
return (0);
}
/*
* scsi_vhci.conf contains mpxio-disable property only in s9 and
* s8+sfkpatch. This property is no longer present from s10 onwards.
*/
if (mpxio_disable == 1) {
/* upgrading from s8 or s9 with mpxio globally disabled */
return (1);
} else if (mpxio_disable == 0) {
/* upgrading from s8 or s9 with mpxio globally enabled */
} else {
/*
* We are looking at the s10 version of the file. This is
* the case if this function is called after installing the
* new scsi_vhci.conf file.
*/
}
!= -1)
return (mpxio_disable);
return (-1);
*p = '\0';
!= -1) {
*p = '/';
return (mpxio_disable);
}
*p = '/';
/*
* mpxio-disable setting is not found in the .conf files.
* The default is to enable mpxio, except if the path is on the root
* controller.
*
* In s8 and s9 mpxio is not supported on the root controller.
* NWS supplies a patch to enable root controller support in s8 and s9.
* If the system had the patch installed, the fp.conf file would have
* explicit "mpxio-disable=no" for the root controller. So we would
* have found the mpxio-disable setting when we looked up this property
* in the fp.conf file.
*/
if (check_root_controller) {
logdmsg(("is_mpxio_disabled: is_root_controller returned %d\n",
} else
mpxio_disable = 0;
return (mpxio_disable);
}
static int
{
return (-1);
return (rv);
}
/*
* Convert a phci client name to vhci client name.
*
* phci_name phci client /devices name without the /devices prefix and
* minor name component.
* ex: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
*
* Returns on success, vhci client name is returned. The memory for
* the vhci name is allocated by this function and the caller
* must free it.
* on failure, NULL is returned.
*/
static char *
{
return (NULL);
*slash = '\0';
addr++;
logdmsg(("phci_to_vhci: vhci_ctl failed: %s\n",
return (NULL);
}
return (retp);
}
static int
char *node_name)
{
int rv = 0;
while (npaths--) {
return (-1);
phci_list++;
rv++;
}
pi++;
}
return (rv);
}
static void
{
char **p;
free(*p);
}
}
/*
* Convert a vhci client name to phci client names.
*
* vhci_name vhci client /devices name without the /devices prefix and
* minor name component.
* num_paths On return, *num_paths is set to the number paths in the
* returned path list.
*
* Returns NULL terminated path list containing phci client paths is
* returned on success. The memory for the path list is
* allocated by this function and the caller must free it by
* calling free_pathlist().
* NULL is returned on failure.
*/
static char **
{
int n;
*num_paths = 0;
/* first get the number paths */
npaths == 0) {
logdmsg(("vhci_to_phci: vhci_ctl failed to get npaths: %s\n",
return (NULL);
}
/* now allocate memory for the path information and get all paths */
sizeof (sv_path_info_t))) == NULL)
return (NULL);
npaths == 0) {
logdmsg(("vhci_to_phci: vhci_ctl failed: %s\n",
goto out;
}
goto out;
node_name++;
*at = '\0';
/* allocate one more (than npaths) for the terminating NULL pointer */
goto out;
/*
* add only online paths as non-online paths may not be accessible
* in the target environment.
*/
MDI_PATHINFO_STATE_ONLINE, node_name)) <= 0)
goto out;
*num_paths = n;
#ifdef DEBUG
logdmsg(("vhci_to_phci: phci list:\n"));
#endif
return (phci_list);
out:
if (phci_list)
return (NULL);
}
/*
* build list of paths accessible from the target environment
*/
static int
{
int mpxio_disabled;
int i, j;
for (i = 0; i < npaths; i++) {
logdmsg(("build_pathlist: mpxio_disabled = %d "
if (mpxio_disabled == -1)
return (-1);
if (mpxio_disabled == 0) {
/*
* mpxio is enabled on this phci path.
* So use vhci path instead of phci path.
*/
return (-1);
/* keep vhci path at beginning of the list */
for (j = i; j > 0; j--)
} else {
npaths--;
for (j = i; j < npaths; j++)
/* compensate for i++ in the for loop */
i--;
}
}
}
#ifdef DEBUG
#endif
return (npaths);
}
/*
* Check if the specified device is refenced in the vfstab file.
* Return 1 if referenced, 0 if not.
*
* rootdir root directory of the target environment
* nodepath /devices path of a device in the target environment without
* the /devices prefix and minor component.
*/
static int
{
int linksize;
logdmsg(("is_dev_in_vfstab: rootdir = %s, nodepath = %s\n",
return (0);
/*
* read device specials from vfstab and compare names at physical
* node path level.
*/
sizeof (SLASH_DEV_SLASH) - 1) == 0) {
SLASH_DEVICES_SLASH)) == NULL)
continue;
} else
continue;
sizeof (SLASH_DEVICES_SLASH) - 1) == 0) {
} else
continue;
/* point to / after /devices */
/* strip minor component */
*minor = '\0';
logdmsg(("is_dev_in_vfstab: returning 1\n"));
return (1);
}
}
return (0);
}
#endif /* __sparc */
static int
{
const char *link;
return (DI_WALK_CONTINUE);
}
/*
* Get the /dev name in the install environment corresponding to physpath.
*
* physpath /devices path in the install environment without the /devices
* prefix.
* buf caller supplied buffer where the /dev name is placed on return
* bufsz length of the buffer
*
* Returns strlen of the /dev name on success, -1 on failure.
*/
static int
{
int tries = 0;
/*
* devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
* after dev link creation. So wait for minimum that amout of time.
*/
logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
return (-1);
}
devname[0] = '\0';
devname, devlink_callback) == 0) {
tries++;
(void) di_devlink_fini(&devlink_hdl);
goto retry;
} else if (devname[0] == '\0') {
logdmsg(("get_install_devlink: di_devlink_walk"
(void) di_devlink_fini(&devlink_hdl);
return (-1);
}
} else {
logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
(void) di_devlink_fini(&devlink_hdl);
return (-1);
}
(void) di_devlink_fini(&devlink_hdl);
}
/*
* Get the /dev name in the target environment corresponding to physpath.
*
* rootdir root directory of the target environment
* physpath /devices path in the target environment without the /devices
* prefix.
* buf caller supplied buffer where the /dev name is placed on return
* bufsz length of the buffer
*
* Returns strlen of the /dev name on success, -1 on failure.
*/
static int
{
char *p;
int linksize;
logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
return (-1);
} else {
}
return (-1);
continue;
physpath) == 0) {
logdmsg(("get_target_devlink: devlink = %s\n",
bufsz));
}
}
}
return (-1);
}
/*
* Convert device name to physpath.
*
* rootdir root directory
* devname a /dev name or /devices name under rootdir
* physpath caller supplied buffer where the /devices path will be placed
* on return (without the /devices prefix).
* physpathlen length of the physpath buffer
*
* Returns 0 on success, -1 on failure.
*/
static int
{
int linksize;
char *p;
logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
if (*rootdir == '\0')
else {
}
== NULL)
return (-1);
} else
return (-1);
} else
p = devname;
return (0);
}
/*
* Map a device name (devname) from the target environment to the
* install environment.
*
* rootdir root directory of the target environment
* devname /dev or /devices name under the target environment
* buf caller supplied buffer where the mapped /dev name is placed
* on return
* bufsz length of the buffer
*
* Returns strlen of the mapped /dev name on success, -1 on failure.
*/
int
{
logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
return (-1);
rootdir = "";
MAXPATHLEN) != 0)
return (-1);
#ifdef __sparc
/* strip minor component if present */
*minor = '\0';
minor++;
}
if (minor)
else
logdmsg(("devfs_target2install: mapped physpath: %s\n",
physpath));
} else if (minor)
}
#endif /* __sparc */
}
/*
* Map a device name (devname) from the install environment to the target
* environment.
*
* rootdir root directory of the target environment
* devname /dev or /devices name under the install environment
* buf caller supplied buffer where the mapped /dev name is placed
* on return
* bufsz length of the buffer
*
* Returns strlen of the mapped /dev name on success, -1 on failure.
*/
int
{
logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
return (-1);
rootdir = "";
return (-1);
#ifdef __sparc
char **pathlist;
int npaths, i, j;
char *minor;
/* strip minor component if present */
*minor = '\0';
minor++;
}
return (-1);
return (-1);
}
/*
* in case of more than one path, try to use the path
* referenced in the vfstab file, otherwise use the first path.
*/
j = 0;
if (npaths > 1) {
for (i = 0; i < npaths; i++) {
if (is_dev_in_vfstab((char *)rootdir,
pathlist[i])) {
j = i;
break;
}
}
}
if (minor)
else
}
#endif /* __sparc */
}
/*
* A parser for /etc/path_to_inst.
* The user-supplied callback is called once for each entry in the file.
* Callback may return DI_WALK_TERMINATE to terminate the walk,
* otherwise DI_WALK_CONTINUE.
*/
int
int (*callback)(void *, const char *, int,
const char *), void *cb_arg)
{
char *devpath;
char *bindname;
int instval = 0;
int rv;
return (ENOMEM);
return (ENOMEM);
}
return (errno);
}
state = STATE_RESET;
switch (token) {
case T_POUND:
/*
* Skip comments.
*/
break;
case T_NAME:
case T_STRING:
switch (state) {
case STATE_RESET:
MAXPATHLEN) >= MAXPATHLEN)
goto err;
break;
case STATE_INSTVAL:
goto err;
if (rv == DI_WALK_TERMINATE)
goto done;
if (rv != DI_WALK_CONTINUE)
goto err;
state = STATE_RESET;
break;
default:
state = STATE_RESET;
break;
}
break;
case T_DECVAL:
case T_HEXVAL:
switch (state) {
case STATE_DEVPATH:
break;
default:
state = STATE_RESET;
break;
}
break;
case T_NEWLINE:
state = STATE_RESET;
break;
default:
state = STATE_RESET;
break;
}
}
done:
return (0);
err:
return (EINVAL);
}
/*
* Walk the minor nodes of all children below the specified device
* by calling the provided callback with the path to each minor.
*/
static int
{
int need_close = 0;
int rv;
return (ENOMEM);
goto err;
}
need_close = 1;
continue;
continue;
(const char *)minor_path, st,
if (rv != 0)
goto err;
if (*terminate)
break;
} else {
if (rv == DI_WALK_TERMINATE) {
*terminate = 1;
break;
}
if (rv != DI_WALK_CONTINUE) {
goto err;
}
}
}
rv = 0;
err:
if (need_close)
if (minor_path)
return (rv);
}
/*
* Return the path to each minor node for a device by
* calling the provided callback.
*/
static int
{
char *minor_path;
char *devpath;
char *expr;
int need_regfree = 0;
int need_close = 0;
int rv;
char *p;
goto err;
}
goto err;
goto err;
*p++ = 0;
if (strlen(p) == 0)
goto err;
goto err;
goto err;
need_regfree = 1;
goto err;
}
need_close = 1;
continue;
continue;
if (rv == DI_WALK_TERMINATE) {
*terminate = 1;
break;
}
if (rv != DI_WALK_CONTINUE) {
goto err;
}
}
}
rv = 0;
err:
if (need_close)
if (need_regfree)
if (devpath)
if (minor_path)
if (expr)
return (rv);
}
/*
* Perform a walk of all minor nodes for the specified device,
* and minor nodes below the device.
*/
int
{
int rv;
int terminate = 0;
}
return (rv);
}
#ifdef DEBUG
static void
{
struct tm t;
if (!devfsmap_debug)
return;
if (*devfsmap_logfile != '\0') {
if (logfp)
}
}
(void) localtime_r(&clock, &t);
t.tm_sec);
}
static void
{
}
#ifdef __sparc
static char *
{
if (mpxio_disable == 0)
return ("no");
else if (mpxio_disable == 1)
return ("yes");
else
return ("not specified");
}
static void
int global_mpxio_disable)
{
if (global_mpxio_disable != -1)
log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
if (confent->unit_address)
log_debug_msg("\tunit_address = %s\n",
log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
}
}
static void
{
char **p;
log_debug_msg("\t%s\n", *p);
}
#endif /* __sparc */
#endif /* DEBUG */