stmsboot_util.c revision 60fffc19b6d98cdde54f6ad4c249f6cd4560d04b
/*
* 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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stropts.h>
#include <strings.h>
#include <dirent.h>
#include <libdevinfo.h>
#include <libgen.h>
#include <dlfcn.h>
#include <link.h>
#include <locale.h>
#include <libintl.h>
#include <devid.h>
#include <sys/libdevid.h>
#define VHCI_CTL_NODE "/devices/scsi_vhci:devctl"
#define SLASH_DEVICES "/devices/"
#ifdef sparc
#define DISK_NODE_NAME "ssd"
#define DISK_DRV_NAME "ssd"
#define SLASH_DISK_AT "/ssd@"
#else /* sparc */
#define DISK_NODE_NAME "disk"
#define DISK_DRV_NAME "sd"
#define SLASH_DISK_AT "/disk@"
#endif
#define DISK_AT_G "disk@g"
#define SLASH_FP_AT "/fp@"
#define SLASH_SCSI_VHCI "/scsi_vhci"
#define SLASH_SD_AT "/sd@"
#define SYS_FILENAME_LEN 256
/*
* Save directory is the directory in which system files are saved.
* Save directory must be under the root filesystem, as this program is
* typically run before any other filesystems are mounted.
*/
/* fcp driver publishes this property */
#define NODE_WWN_PROP "node-wwn"
/*
* For SAS, we look for "sas-$drivername", eg sas-mpt, but
* we strncat the driver name later once we've parsed the
* args passed in from the shell.
*/
#define SASPROP "sas-"
typedef enum {
struct devlink_cbarg {
char *devlink;
};
static int vhci_fd = -1;
static char *mapdev = "";
static char *map_vhciname = "";
static char *stmsboot = "stmsboot";
/* "node-wwn" if drvname=fp, or "sas-$drivername" otherwise */
static int parent = 0; /* for "-n" usage */
static void commit_change(char *, char *, char *, int);
static int map_devname(char *, char *, size_t, int);
static int update_vfstab(char *, char *);
static int list_mappings(int, int);
static int canopen(char *);
static void list_nodes(char *drivername);
static void logerr(char *, ...);
static void logdmsg(char *, ...);
static char *s_strdup(const char *);
static int map_openable_vhciname(char *, char *, size_t);
/*
* Using an exit function not marked __NORETURN causes a warning with gcc.
* To suppress the warning, use __NORETURN attribute.
*/
static void clean_exit(int)__NORETURN;
/*
* Print usage and exit.
*/
static void
{
char *progname;
progname++;
else
/*
* -m devname
* if devname is phci based name and not open-able, map it to
* vhci based /devices name.
* if devname is vhci based name and not open-able, map it to
* phci based /devices name.
* -M devname
* same as -m except that /dev link is printed instead of
* /devices name.
* -l controller
* list non-STMS to STMS device name mappings for the specific
* controller
* -L list non-STMS to STMS device name mappings for all controllers
* -p devname
* if devname is vhci based name and open-able, get the first
* onlined phci based name without /devices prefix.
* Used in stmsboot to update the phci based bootpath.
* -D drvname
* if supplied, indicates that we're going to operate on
* devices attached to this driver
* -n
* if supplied, returns name of the node containing "fp" or
* "sas-$driver", appends "sd@" or "ssd@" or "disk@". Can only
* be used if -D drv is specified as well
*/
"-M devname | -l controller | -L | \n"
"\t\t-p devname | -D { fp | mpt } | -n\n"), progname);
exit(2);
}
/*
* Parse command line arguments.
*/
static void
{
char opt;
int n = 0;
if (argc == 1) {
/*NOTREACHED*/
}
switch (opt) {
case 'u':
patch_vfstab = 1;
n++;
break;
case 'd':
debug = 1;
break;
case 'm':
n++;
break;
case 'M':
cap_m_option = 1;
n++;
break;
case 'L':
list_option = 1;
n++;
break;
case 'l':
list_option = 1;
if (list_controllernum < 0) {
"invalid\n"), list_controllernum);
clean_exit(1);
}
n++;
break;
case 'g':
/*
* private option to display non-STMS device name
* to GUID mappings.
*/
list_guid_mappings = 1;
break;
case 'p':
/*
* map openable vhci based name to phci base name
*/
n++;
break;
case 'D':
/*
* Grab the driver name we need to look for. Each
* time we add support for a new SAS or FC driver
* to this utility, make sure that its driver name
* is checked here.
*/
sizeof (drvname) + 1);
sizeof (drvname), "%s%s",
} else {
drvname);
clean_exit(1);
}
break;
case 'n':
++parent;
n++;
break;
default:
/*NOTREACHED*/
}
}
if (n != 1) {
/*NOTREACHED*/
}
}
int
{
int vfstab_updated;
(void) textdomain(TEXT_DOMAIN);
if (getuid() != 0) {
clean_exit(1);
}
(void) umask(022);
/*
* NOTE: The mpxio boot-up script executes this program with the
* mapping (-m) option before the /usr is even mounted and when the
* root filesystem is still mounted read-only.
*/
if (*mapdev != '\0') {
char newname[MAXPATHLEN];
cap_m_option) == 0) {
clean_exit(0);
}
clean_exit(1);
}
if (*map_vhciname != '\0') {
char newname[MAXPATHLEN];
sizeof (newname)) == 0) {
clean_exit(0);
}
clean_exit(1);
}
if (list_option || list_guid_mappings) {
clean_exit(0);
clean_exit(1);
}
if (parent > 0) {
clean_exit(1);
} else {
clean_exit(0);
}
}
/* create a directory where a copy of the system files are saved */
if (patch_vfstab) {
clean_exit(1);
}
SYS_FILENAME_LEN) != 0)
clean_exit(1);
/* build new vfstab without modifying the existing one */
== -1) {
clean_exit(1);
}
}
clean_exit(0);
}
/*
* Make saved and temporary filenames in SAVE_DIR.
*
* would be SAVE_DIR/vfstab and SAVE_DIR/vfstab.tmp respectively.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char *ptr;
return (-1);
}
return (0);
}
/*
* Commit the changes made to the system file
*/
static void
int updated)
{
int x;
if (updated) {
/* save the original */
}
/* now rename the new file to the actual file */
/* restore the original */
gettext("rename %1$s to %2$s failed: %3$s\n"
"%4$s is a copy of the original %5$s file"
"\n"),
}
} else
} else {
/* remove the temp file */
(void) unlink(tmp_filename);
}
}
/*
* Get the GUID of the device.
*
* physpath /devices name without the /devices prefix and minor name
* component.
* guid caller supplied buffer where the GUID will be placed on return
* guid_len length of the caller supplied guid buffer.
* no_delay_flag if set open the device with O_NDELAY
* node di_node corresponding to physpath if already available,
* otherwise pass DI_NODE_NIL.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
int fd;
int rv = -1;
char physpath_raw[MAXPATHLEN];
int i, n, snapshot_taken = 0;
#ifdef sparc
"/devices%s:a,raw", physpath);
#else
"/devices%s:c,raw", physpath);
#endif
*guid = '\0';
if (no_delay_flag)
/*
* Open the raw device
* Without the O_DELAY flag, the open will fail on standby paths of
* T3 if its mp_support mode is "mpxio".
*/
return (-1);
}
rv = 0;
goto out;
} else {
logdmsg("get_guid: devid_to_guid() failed\n");
logdmsg("Unable to get a GUID for device "
"%s\n", physpath_raw);
}
} else
/*
* Unless we're looking at an fp-attached device, we now
* fallback to node name as the guid as this is what the
* fcp driver does. A sas-attached device will have the
* client-guid property set.
*/
if (node == DI_NODE_NIL) {
== DI_NODE_NIL) {
logdmsg("get_guid: di_init on %s failed: %s\n",
goto out;
}
snapshot_taken = 1;
}
/* non-fp fallout */
"client-guid", &guid) < 0) {
logdmsg("get_guid: non-fp-attached device, "
"bailing out\n");
goto out;
}
}
&wwnp)) == -1) {
logdmsg("get_guid: di_prop_lookup_bytes() failed to lookup "
goto out;
}
for (i = 0; i < n; i++) {
wwnp++;
}
rv = 0;
} else
out:
if (snapshot_taken)
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
* on sparc:
* other CLIENT_TYPE_UNKNOWN
* on x86:
* other CLIENT_TYPE_UNKNOWN
*/
static client_type_t
client_name_type(char *client_name)
{
char *p1;
char *client_path;
if (*client_name != '/')
return (CLIENT_TYPE_UNKNOWN);
return (CLIENT_TYPE_UNKNOWN);
}
*p1 = '\0';
/*
* Courtesy of the if (..) block above, we know that any
* device path we have now is either PHCI or VHCI
*/
*p1 = '/';
return (client_type);
}
/*
* client_by_props() is called to determine what the client type
* is, based on properties in the device tree:
*
* drivername property type
* -------------------------------------
* fp node-wwn CLIENT_TYPE_PHCI
* mpt sas-mpt CLIENT_TYPE_PHCI
* mpt client-guid CLIENT_TYPE_PHCI (corner case)
*
* Normally, the "client-guid" property only shows up for a node
* if we've enumerated that node under scsi_vhci. During testing
* of this function, one particular corner case was found which
* requires an exception handler.
*/
static client_type_t
client_by_props(char *path) {
unsigned int rval = CLIENT_TYPE_UNKNOWN;
char *physpath;
char *parentpath;
/* easy short-circuits */
logdmsg("client_by_props: found "
"'scsi_vhci' on path (%s)\n", physpath);
goto out;
logdmsg("client_by_props: ignoring this device\n");
goto out;
}
DINFOFORCE)) == DI_NODE_NIL) {
logdmsg("client_by_props: unable to di_init(%s)\n",
goto out;
}
}
logdmsg("NODE_WWN_PROP\n");
} else {
}
sizeof (drvname) + 1);
}
logdmsg("parentpath: %s\nphyspath: %s\n"
"length %d, strrchr: %d\n",
}
DI_NODE_NIL) {
logdmsg("client_by_props: unable to di_init(%s)\n",
physpath);
/*
* node we want in the device tree, however the parent
* node will still have 'mpxio-disable' set, so we can
* check for that property and make our decision on type
*/
logdmsg("client_by_props: device %s is PHCI\n",
physpath);
}
goto out;
}
logdmsg("client_by_props: found prop %s on "
} else if (di_prop_lookup_strings(DDI_DEV_T_ANY,
/*
* A corner case was seen during testing where
* scsi_vhci was loaded, but not all applicable
* devices were enumerated under it. That left
* the phci mapping along with the "client-guid"
* property.
*/
logdmsg("client_by_props: weird... \n");
} else {
logdmsg("client_by_props: unable to find "
"property 'client-guid', 'mpxio-disable' "
"or '%s' anywhere on path (%s)\n",
logdmsg("client_by_props: this node is unknown\n");
}
out:
return (rval);
}
/*
* Map phci based client name to vhci based client name.
*
* phci_name
* phci based client /devices name without the /devices prefix and
* minor name component.
* ex:
*
* (FC)
* for sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
* for x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
*
* (SAS)
* for sparc: /pci@0,2/LSILogic,sas@1/disk@6,0
* for x86: /pci1000,3060@3/sd@0,0
*
* vhci_name
* Caller supplied buffer where vhci /devices name will be placed on
* return (without the /devices prefix and minor name component).
* ex:
*
* (FC)
*
* (SAS)
*
* vhci_name_len
* Length of the caller supplied vhci_name buffer.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char vhci_name_buf[MAXPATHLEN];
char phci_name_buf[MAXPATHLEN];
char addr_buf[MAXNAMELEN];
logdmsg("phci_to_vhci: %s is not of CLIENT_TYPE_PHCI\n",
return (-1);
}
if (vhci_fd < 0) {
return (-1);
}
*slash = '\0';
logdmsg("SCSI_VHCI_GET_CLIENT_NAME on %s "
return (-1);
}
return (0);
}
/*
* Map vhci based client name to phci based client name.
* If the client has multiple paths, only one of the paths with which client
* can be accessed is returned. This function does not use SCSI_VHCI ioctls
* as it is called on mpxio disabled paths.
*
* vhci_name
* vhci based client /devices name without the /devices prefix and
* minor name component.
* ex:
*
* phci_name
* Caller supplied buffer where phci /devices name will be placed on
* return (without the /devices prefix and minor name component).
* ex:
* sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
* x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
*
* phci_name_len
* Length of the caller supplied phci_name buffer.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char phci_guid[MAXPATHLEN];
char *node_name;
logdmsg("vhci_to_phci: %s is not of CLIENT_TYPE_VHCI\n",
return (-1);
}
*(++vhci_guid) != 'g') {
return (-1);
}
/* point to guid */
++vhci_guid;
/*
* Get devinfo snapshot and walk all ssd nodes whose parent is fp.
* For each node get the guid and match it with vhci_guid.
*/
if (devinfo_root == DI_NODE_NIL) {
logdmsg("vhci_to_phci: taking devinfo snapshot\n");
== DI_NODE_NIL) {
return (-1);
}
logdmsg("vhci_to_phci: done taking devinfo snapshot\n");
}
/*
* When we finally get a unified "sd" driver for all
* architectures that Solaris runs on, we can remove this
* first loop around for "ssd"
*/
continue;
continue;
continue;
continue;
/*
* Don't set no_delay_flag to have get_guid() fail on
* standby paths of T3. So we'll find the preferred paths.
*/
continue;
return (0);
}
}
continue;
continue;
continue;
continue;
/*
* Don't set no_delay_flag to have get_guid() fail on
* standby paths of T3. So we'll find the preferred paths.
*/
continue;
return (0);
}
}
return (-1);
}
/*
* Map vhci based client name to phci based client name.
* If the client has multiple paths, only one of the paths with which client
* can be accessed is returned.
* This function uses SCSI_VHCI ioctls to get the phci paths
*
* vhci_name
* vhci based client /devices name without the /devices prefix and
* minor name component.
* ex:
*
* phci_name
* Caller supplied buffer where phci /devices name will be placed on
* return (without the /devices prefix and minor name component).
* ex:
* sparc: /pci@8,600000/SUNW,qlc@4/fp@0,0/ssd@w2100002037cd9f72,0
* x86: /pci@8,600000/SUNW,qlc@4/fp@0,0/disk@w2100002037cd9f72,0
*
* phci_name_len
* Length of the caller supplied phci_name buffer.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char vhci_name_buf[MAXPATHLEN];
int ret;
if (vhci_fd < 0) {
return (-1);
}
/* first get the number paths */
logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
"failed: %s\n", vhci_name,
return (-1);
}
/* now allocate memory for the path information and get all paths */
sizeof (sv_path_info_t))) == NULL)
return (-1);
logdmsg("SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO on %s "
"failed: %s\n", vhci_name,
goto out;
}
goto out;
node_name++;
*at = '\0';
#ifndef sparc
/*
* We need to use a libdevinfo call to get this info
* in an architecturally-neutral fashion. Phase-II for sure!
*/
node_name = "sd";
#endif
/*
* return the first online paths as non-online paths may
* not be accessible in the target environment.
*/
while (npaths--) {
logdmsg("vhci_to_phci_by_ioctl: %s maps to %s\n",
return (0);
}
pi++;
}
out:
logdmsg("vhci_to_phci_by_ioctl: couldn't get phci name for %s\n",
return (-1);
}
/*
* Map physname from phci name space to vhci name space or vice-versa
*
* physname
* phci or vhci based client /devices name without the /devices prefix and
* minor name component.
*
* new_physname
* Caller supplied buffer where the mapped physical name is stored on
* return (without the /devices prefix and minor name component).
*
* len
* Length of the caller supplied new_physname buffer.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
int type;
int rv;
logdmsg("map_physname: type (%d) physname = %s\n",
if (type == CLIENT_TYPE_VHCI)
else if (type == CLIENT_TYPE_PHCI)
else
rv = -1;
return (rv);
}
/*
* Given a phci or vhci devname which is either a /dev link or /devices name
* get the corresponding physical node path (without the /devices prefix)
* and minor name.
*
* Returns 0 on success, -1 on failure.
*/
static int
char *minorname, int minorname_len)
{
int linksize;
char buf[MAXPATHLEN];
char *p, *m;
} else
return (-1);
} else
return (-1);
/* point to '/' after /devices */
p += sizeof (SLASH_DEVICES) - 2;
logdmsg("get_physname_minor: no minor name component in %s\n",
buf);
return (-1);
}
*m = '\0';
m++;
if (client_name_type(p) == CLIENT_TYPE_UNKNOWN)
return (-1);
logdmsg("get_physname_minor: %s: physname = %s, minor = %s\n",
return (0);
}
static int
{
const char *link;
return (DI_WALK_TERMINATE);
}
return (DI_WALK_CONTINUE);
}
/*
* Lookup the /dev link corresponding to physname and minorname.
*
* physname client /devices path without the /devices prefix and minor
* name component.
* minorname client minor name.
* devlink caller supplied buffer where the /dev link is placed on return.
* len caller supplied devlink buffer length
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char buf[MAXPATHLEN];
struct devlink_cbarg arg;
if (devlink_hdl == NULL) {
logdmsg("lookup_devlink: taking devlink snapshot\n");
clean_exit(1);
}
}
*devlink = '\0';
devlink_callback) != 0) {
logdmsg("lookup_devlink: di_devlink_walk on %s failed: %s\n",
return (-1);
}
if (*devlink == '\0') {
logdmsg("lookup_devlink: failed to lookup devlink for %s\n",
buf);
return (-1);
}
return (0);
}
/*
* open infile for reading and return its file pointer in *fp_in.
* open outfile for writing and return its file pointer in *fp_out.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
goto out;
}
goto out;
}
goto out;
}
goto out;
}
"gid %3$d: %4$s\n"),
goto out;
}
return (0);
out:
return (-1);
}
/*
* If the devname is a phci based name and not open-able, map it to vhci
* based name. If the devname is a vhci based name and not open-able, map it
* to phci based name.
*
* devname either a /dev link or /devices name to client device
* new_devname caller supplied buffer where the mapped device name is
* placed on return.
* len caller supplied new_devname buffer length
* devlink_flag pass 1 if requesting the /dev link to the mapped device.
* pass 0 if requesting the /devices name of the mapped device.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
char physname[MAXPATHLEN];
char minor[MAXNAMELEN];
char new_physname[MAXPATHLEN];
sizeof (new_physname)) == 0)) {
logdmsg("map_devname: now looking up devlink\n");
if (devlink_flag) {
len) == 0)
return (0);
} else {
return (0);
}
}
return (-1);
}
/*
* If the devname is a vhci based name and open-able, map it to phci
* based name.
*
* devname either a /dev link or /devices name to client device
* new_devname caller supplied buffer where the mapped device name without
* /devices prefix is placed on return.
* len caller supplied new_devname buffer length
*/
static int
{
char physname[MAXPATHLEN];
char minor[MAXNAMELEN];
char new_physname[MAXPATHLEN];
sizeof (new_physname)) == 0) {
return (0);
}
return (-1);
}
/*
* Read vfstab_in, convert the device name entries to appropriate vhci or phci
* based names, and write to vfstab_out. Only device names whose physical
* paths are either phci or vhci based names and not open-able are considered
* for conversion. Open-able device name entries are not converted as it
* means that the device is already accessible; hence no need to convert.
*
* Returns:
* 0 successful but vfstab_out contents are the same as vfstab_in
* 1 successful and vfstab_out changed from vfstab_in
* -1 failed
*/
static int
{
char *vfs_cache[2];
int rv = -1;
int vfstab_updated = 0;
int i;
char cdev[MAXPATHLEN];
char bdev[MAXPATHLEN];
char mntpt[MAXPATHLEN];
char fstype[512];
char fsckpass[512];
char mntboot[512];
char mntopt[MAX_MNTOPT_STR];
char new_physname[MAXPATHLEN];
char fmt[80];
return (-1);
/*
* Read one line at time from vfstab_in. If no conversion is needed
* for the line simply write the line to vfstab_out. If conversion is
* needed, first write the existing line as a comment to vfstab_out
* and then write the converted line.
*
* To avoid commented entries piling up in vfstab in case if the
* user runs stmsboot multiple times to switch on and off from mpxio,
* add the commented line only if not already there. To do this
* cache the last two vfstab lines processed and add the commented
* entry only if it is not found in the cache. We only need to cache
* the last two lines because a device can have at most two names -
* one mpxio and one non-mpxio name. Therefore for any device name
* entry we at most add two comments - one with mpxio name and one
* with non-mpxio name - no matter how many times stmsboot is run.
*/
"exceeded %2$d: \"%3$s\"\n"),
goto out;
}
/* LINTED - format specifier */
(bdev[0] == '#') ||
bdev_minor, sizeof (bdev_minor)) != 0) ||
cdev_minor, sizeof (cdev_minor)) != 0) ||
sizeof (new_physname)) != 0) ||
sizeof (new_bdevlink)) != 0) ||
sizeof (new_cdevlink)) != 0))) {
/* cache the last two entries */
if (count < 2)
count++;
"failed: %3$s\n"),
goto out;
}
} else {
/*
* comment the entry in vfstab only if it is not
* already in the cache.
*/
"# mpxio: %s", buf);
else
"# non-mpxio: %s", buf);
for (i = 0; i < count; i++) {
break;
}
if (i == count) {
"failed: %3$s\n"), tmpbuf,
goto out;
}
}
count = 0;
idx = 0;
"%1$s: %2$s\n"),
goto out;
}
vfstab_updated = 1;
}
}
rv = vfstab_updated;
out:
return (rv);
}
/*
* if guidmap is 0, list non-STMS to STMS device name mappings for the
* specified controller.
* if guidmap is 1, list non-STMS to GUID mappings for the specified controller.
* If controller is -1 list mappings for all controllers.
*
* Returns 0 on success, -1 on failure.
*/
static int
{
int header = 1;
char devname[MAXPATHLEN];
char physname[MAXPATHLEN];
char new_devname[MAXPATHLEN];
char new_physname[MAXPATHLEN];
char guid[MAXPATHLEN];
char minor[MAXNAMELEN];
return (-1);
continue;
logdmsg("list_mappings: continuing\n");
continue;
}
/*
* First try phci_to_vhci() mapping. It will work if the
* device is under MPxIO control. If the device is not under
* MPxIO, phci_to_vhci() will fail in which case try to lookup
* if an old mapping exists using guid lookup.
*/
mapped = 1;
sizeof (new_physname)) != 0) {
DI_NODE_NIL) == 0)
else
mapped = 0;
}
if (mapped == 0)
continue;
/* strip the slice number part */
if (guidmap == 0) {
new_devname, sizeof (new_devname)) != 0)
continue;
/* strip the slice number part */
if (header) {
(void) printf(
gettext("non-STMS device name\t\t\t"
"STMS device name\n"
"------------------------------------------"
"------------------------\n"));
header = 0;
}
} else {
/* extract guid part */
/* we should be using a getguid() call instead */
== NULL) {
continue;
}
*p2 = '\0';
if (header) {
(void) printf(
gettext("non-STMS device name\t\t\tGUID\n"
"------------------------------------------"
"------------------------\n"));
header = 0;
}
}
}
return (0);
}
/*
* Check if the file can be opened.
*
* Return 1 if the file can be opened, 0 otherwise.
*/
static int
{
int fd;
return (0);
return (1);
}
/*
* This function traverses the device tree looking for nodes
* which have "drivername" as a property. We return a list of
* these nodes, with SLASH_DISK_AT appended.
* combinations, we have to be smart about returning only those
* drivername is "fp", in which case we're searching for "node-wwn"
*/
static void
list_nodes(char *drivername)
{
char *aliaslist;
int i = 1; /* fencepost */
/*
* Since the "fp" driver enumerates with its own name,
* we can special-case its handling.
*/
} else {
== DI_NODE_NIL) {
}
!= NULL) {
logdmsg("list_nodes: searching for property "
"%s\n", drvprop);
while (thisnode != DI_NODE_NIL) {
logdmsg("devfs-name %s driver-name %s "
"node-name %s\n",
/* We check the child node for drvprop */
&intprop) > -1) ||
drivername)) == 0)) {
== (char *)NULL) {
char *nname;
if (i) {
--i;
} else {
di_node_name(thisnode)) ==
(char *)NULL) {
"%s|%s", aliaslist,
nname);
}
}
}
} else {
logdmsg("unable to lookup property %s "
"for node %s. Error %d: %s\n",
}
}
}
}
}
static void
{
/* LINTED - format specifier */
}
/* log debug message */
static void
{
if (debug) {
/* LINTED - format specifier */
}
}
static void *
{
void *rp;
clean_exit(1);
}
return (rp);
}
static char *
{
void *rp;
clean_exit(1);
}
return (rp);
}
static void
{
int n;
clean_exit(1);
}
}
static void
clean_exit(int status)
{
if (devinfo_root != DI_NODE_NIL)
if (devlink_hdl != NULL)
(void) di_devlink_fini(&devlink_hdl);
if (vhci_fd != -1)
}