2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include "cfga_scsi.h"
2N/A
2N/Atypedef struct {
2N/A char *dyncomp;
2N/A char *devlink;
2N/A int l_errno;
2N/A scfga_ret_t ret;
2N/A} dyn_t;
2N/A
2N/Atypedef struct {
2N/A scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp);
2N/A scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp);
2N/A} dynrules_t;
2N/A
2N/Atypedef struct {
2N/A dyn_t *dynp;
2N/A dynrules_t *rule_array;
2N/A int nrules;
2N/A} dyncvt_t;
2N/A
2N/Atypedef struct {
2N/A const char *hba_phys;
2N/A const char *dyncomp;
2N/A char *path;
2N/A int l_errno;
2N/A scfga_ret_t ret;
2N/A} devpath_t;
2N/A
2N/A
2N/A
2N/A/* Function prototypes */
2N/A
2N/Astatic int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg);
2N/Astatic scfga_ret_t drv_dyn_to_devpath(const char *hba_phys,
2N/A const char *dyncomp, char **pathpp, int *l_errnop);
2N/Astatic int do_drv_dyn_to_devpath(di_node_t node, void *arg);
2N/Astatic scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys,
2N/A const char *dyncomp, char **pathpp, int *l_errnop);
2N/A
2N/Astatic scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp);
2N/Astatic scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp);
2N/Astatic scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp);
2N/A
2N/Astatic scfga_ret_t devlink_to_dyncomp(char *devlink,
2N/A char **dyncompp, int *l_errnop);
2N/Astatic scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp);
2N/Astatic scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp);
2N/Astatic scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp);
2N/Astatic scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys,
2N/A char **dyncompp, int *l_errnop);
2N/Astatic scfga_ret_t get_hba_devlink(const char *hba_phys,
2N/A char **hba_logpp, int *l_errnop);
2N/Astatic scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn,
2N/A char **pathpp, int *l_errnop);
2N/A
2N/A
2N/A/* Globals */
2N/A
2N/A/*
2N/A * Rules for converting between a devlink and logical ap_id and vice-versa
2N/A * The default rules must be the last entry.
2N/A */
2N/Astatic dynrules_t dyncvt_rules[] = {
2N/A {disk_devlink_to_dyncomp, disk_dyncomp_to_devlink},
2N/A {tape_devlink_to_dyncomp, tape_dyncomp_to_devlink},
2N/A {def_devlink_to_dyncomp, def_dyncomp_to_devlink}
2N/A};
2N/A
2N/A#define N_DYNRULES (sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0]))
2N/A
2N/A/*
2N/A * Numbering of disk slices is assumed to be 0 through n - 1
2N/A */
2N/Atypedef struct {
2N/A char *prefix;
2N/A int nslices;
2N/A} slice_t;
2N/A
2N/Astatic slice_t disk_slices[] = {
2N/A {"s", 16},
2N/A {"p", 5},
2N/A};
2N/A
2N/A#define N_SLICE_TYPES (sizeof (disk_slices) / sizeof (disk_slices[0]))
2N/A
2N/Astatic const char *tape_modes[] = {
2N/A "",
2N/A "b", "bn",
2N/A "c", "cb", "cbn", "cn",
2N/A "h", "hb", "hbn", "hn",
2N/A "l", "lb", "lbn", "ln",
2N/A "m", "mb", "mbn", "mn",
2N/A "n",
2N/A "u", "ub", "ubn", "un"
2N/A};
2N/A
2N/A#define N_TAPE_MODES (sizeof (tape_modes) / sizeof (tape_modes[0]))
2N/A
2N/A
2N/A/* Various conversions routines */
2N/A
2N/A/*
2N/A * Generates the HBA logical ap_id from physical ap_id.
2N/A */
2N/Ascfga_ret_t
2N/Amake_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop)
2N/A{
2N/A walkarg_t u;
2N/A pathm_t pmt = {NULL};
2N/A scfga_ret_t ret;
2N/A
2N/A
2N/A if (*hba_logpp != NULL) {
2N/A return (SCFGA_ERR);
2N/A }
2N/A
2N/A /* A devlink for the HBA may or may not exist */
2N/A if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) {
2N/A assert(*hba_logpp != NULL);
2N/A return (SCFGA_OK);
2N/A }
2N/A
2N/A /*
2N/A * No devlink based logical ap_id.
2N/A * Try driver name and instance number.
2N/A */
2N/A u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT;
2N/A u.minor_args.fcn = drv_to_hba_logid;
2N/A
2N/A pmt.phys = (char *)hba_phys;
2N/A pmt.ret = SCFGA_APID_NOEXIST;
2N/A
2N/A errno = 0;
2N/A ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u,
2N/A SCFGA_WALK_MINOR, &pmt.l_errno);
2N/A if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) {
2N/A assert(pmt.log != NULL);
2N/A *hba_logpp = pmt.log;
2N/A return (SCFGA_OK);
2N/A }
2N/A
2N/A /* failed to create logical ap_id */
2N/A if (pmt.log != NULL) {
2N/A S_FREE(pmt.log);
2N/A }
2N/A
2N/A
2N/A *l_errnop = pmt.l_errno;
2N/A return (ret);
2N/A}
2N/A
2N/Astatic scfga_ret_t
2N/Aget_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop)
2N/A{
2N/A size_t len;
2N/A scfga_ret_t ret;
2N/A int match_minor = 1;
2N/A
2N/A ret = physpath_to_devlink((char *)hba_phys, hba_logpp,
2N/A l_errnop, match_minor);
2N/A if (ret != SCFGA_OK) {
2N/A return (ret);
2N/A }
2N/A
2N/A assert(*hba_logpp != NULL);
2N/A
2N/A /* Remove the "/dev/cfg/" prefix */
2N/A len = strlen(CFGA_DEV_DIR SLASH);
2N/A
2N/A (void) memmove(*hba_logpp, *hba_logpp + len,
2N/A strlen(*hba_logpp + len) + 1);
2N/A
2N/A return (SCFGA_OK);
2N/A}
2N/A
2N/A/* Make logical name for HBA based on driver and instance */
2N/Astatic int
2N/Adrv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg)
2N/A{
2N/A int inst;
2N/A char *drv, *mn, *log;
2N/A pathm_t *ptp;
2N/A const size_t loglen = MAXPATHLEN;
2N/A
2N/A ptp = (pathm_t *)arg;
2N/A
2N/A errno = 0;
2N/A
2N/A mn = di_minor_name(minor);
2N/A drv = di_driver_name(node);
2N/A inst = di_instance(node);
2N/A log = calloc(1, loglen);
2N/A
2N/A if (mn != NULL && drv != NULL && inst != -1 && log != NULL) {
2N/A /* Count does not include terminating NULL */
2N/A if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) {
2N/A ptp->ret = SCFGA_OK;
2N/A ptp->log = log;
2N/A return (DI_WALK_TERMINATE);
2N/A }
2N/A }
2N/A
2N/A S_FREE(log);
2N/A return (DI_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical
2N/A * path in pathpp.
2N/A * Returns: SCFGA_APID_NOEXIST if the path does not exist.
2N/A */
2N/A
2N/Ascfga_ret_t
2N/Aapid_to_path(
2N/A const char *hba_phys,
2N/A const char *dyncomp,
2N/A char **pathpp,
2N/A int *l_errnop)
2N/A{
2N/A scfga_ret_t ret;
2N/A
2N/A if (*pathpp != NULL) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A /* If a bus, the physical ap_id is the physical path */
2N/A if (dyncomp == NULL) {
2N/A if ((*pathpp = strdup(hba_phys)) == NULL) {
2N/A *l_errnop = errno;
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A return (SCFGA_OK);
2N/A }
2N/A
2N/A /* Dynamic component exists, we have a device */
2N/A
2N/A /*
2N/A * If the dynamic component has a '/', it was derived from a devlink
2N/A * Else it was derived from driver name and instance number.
2N/A * If it is pathinfo instance number based ap id, it will have a format
2N/A * path#.???.
2N/A */
2N/A if (strchr(dyncomp, '/') != NULL) {
2N/A ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp,
2N/A l_errnop);
2N/A } else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
2N/A ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp,
2N/A l_errnop);
2N/A } else {
2N/A ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop);
2N/A }
2N/A assert(ret != SCFGA_OK || *pathpp != NULL);
2N/A
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Get the devfs path of pathinfo node that is associated with
2N/A * the given dynamic component.
2N/A *
2N/A * input
2N/A * hba_phys: physical path of HBA
2N/A * dyn : bus address of pathinfo node
2N/A * output:
2N/A * pathpp: devfs path of the pathinfo node.
2N/A */
2N/Astatic scfga_ret_t
2N/Apath_apid_dyn_to_path(
2N/A const char *hba_phys,
2N/A const char *dyn,
2N/A char **pathpp,
2N/A int *l_errnop)
2N/A{
2N/A
2N/A di_node_t root, walk_root;
2N/A di_path_t pi_node = DI_PATH_NIL;
2N/A char *root_path, *devpath, *cp;
2N/A int len;
2N/A
2N/A *l_errnop = 0;
2N/A
2N/A /* *pathpp should be NULL if pathpp is not NULL. */
2N/A if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A if ((root_path = strdup(hba_phys)) == NULL) {
2N/A *l_errnop = errno;
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A /* Fix up path for di_init() */
2N/A len = strlen(DEVICES_DIR);
2N/A if (strncmp(root_path, DEVICES_DIR SLASH,
2N/A len + strlen(SLASH)) == 0) {
2N/A cp = root_path + len;
2N/A (void) memmove(root_path, cp, strlen(cp) + 1);
2N/A } else if (*root_path != '/') {
2N/A *l_errnop = 0;
2N/A S_FREE(root_path);
2N/A return (SCFGA_ERR);
2N/A }
2N/A
2N/A /* Remove dynamic component if any */
2N/A if ((cp = GET_DYN(root_path)) != NULL) {
2N/A *cp = '\0';
2N/A }
2N/A
2N/A /* Remove minor name if any */
2N/A if ((cp = strrchr(root_path, ':')) != NULL) {
2N/A *cp = '\0';
2N/A }
2N/A
2N/A /*
2N/A * Cached snapshots are always rooted at "/"
2N/A */
2N/A
2N/A /* Get a snapshot */
2N/A if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
2N/A *l_errnop = errno;
2N/A S_FREE(root_path);
2N/A return (SCFGA_ERR);
2N/A }
2N/A
2N/A /*
2N/A * Lookup the subtree of interest
2N/A */
2N/A walk_root = di_lookup_node(root, root_path);
2N/A
2N/A if (walk_root == DI_NODE_NIL) {
2N/A *l_errnop = errno;
2N/A di_fini(root);
2N/A S_FREE(root_path);
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A S_FREE(root_path);
2N/A
2N/A if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
2N/A DI_PATH_NIL) {
2N/A di_fini(root);
2N/A return (SCFGA_APID_NOEXIST);
2N/A }
2N/A
2N/A /*
2N/A * now parse the path info node.
2N/A */
2N/A do {
2N/A /* check the length first. */
2N/A if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) {
2N/A continue;
2N/A }
2N/A
2N/A if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) {
2N/A /* get the devfspath of pathinfo node. */
2N/A devpath = di_path_devfs_path(pi_node);
2N/A if (devpath == NULL) {
2N/A *l_errnop = errno;
2N/A di_fini(root);
2N/A return (SCFGA_ERR);
2N/A }
2N/A
2N/A len = strlen(DEVICES_DIR) + strlen(devpath) + 1;
2N/A *pathpp = calloc(1, len);
2N/A if (*pathpp == NULL) {
2N/A *l_errnop = errno;
2N/A di_devfs_path_free(devpath);
2N/A di_fini(root);
2N/A return (SCFGA_ERR);
2N/A } else {
2N/A (void) snprintf(*pathpp, len, "%s%s",
2N/A DEVICES_DIR, devpath);
2N/A di_devfs_path_free(devpath);
2N/A di_fini(root);
2N/A return (SCFGA_OK);
2N/A }
2N/A }
2N/A pi_node = di_path_next_client(walk_root, pi_node);
2N/A } while (pi_node != DI_PATH_NIL);
2N/A
2N/A di_fini(root);
2N/A return (SCFGA_APID_NOEXIST);
2N/A}
2N/A
2N/Astatic scfga_ret_t
2N/Adrv_dyn_to_devpath(
2N/A const char *hba_phys,
2N/A const char *dyncomp,
2N/A char **pathpp,
2N/A int *l_errnop)
2N/A{
2N/A walkarg_t u;
2N/A devpath_t dpt = {NULL};
2N/A scfga_ret_t ret;
2N/A
2N/A /* A device MUST have a dynamic component */
2N/A if (dyncomp == NULL || *pathpp != NULL) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A u.node_args.flags = DI_WALK_CLDFIRST;
2N/A u.node_args.fcn = do_drv_dyn_to_devpath;
2N/A
2N/A dpt.hba_phys = hba_phys;
2N/A dpt.dyncomp = dyncomp;
2N/A dpt.ret = SCFGA_APID_NOEXIST;
2N/A
2N/A ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u,
2N/A SCFGA_WALK_NODE, &dpt.l_errno);
2N/A
2N/A if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) {
2N/A assert(dpt.path != NULL);
2N/A *pathpp = dpt.path;
2N/A return (SCFGA_OK);
2N/A }
2N/A
2N/A if (dpt.path != NULL) {
2N/A S_FREE(dpt.path);
2N/A }
2N/A
2N/A
2N/A *l_errnop = dpt.l_errno;
2N/A return (ret);
2N/A}
2N/A
2N/A/* Converts a driver and instance number based logid into a physical path */
2N/Astatic int
2N/Ado_drv_dyn_to_devpath(di_node_t node, void *arg)
2N/A{
2N/A int inst, rv, match_minor;
2N/A devpath_t *dptp;
2N/A char *physpath, *drv;
2N/A char *drvinst, *devpath;
2N/A const size_t drvlen = MAXPATHLEN;
2N/A size_t devlen;
2N/A
2N/A dptp = (devpath_t *)arg;
2N/A
2N/A assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL);
2N/A assert(dptp->path == NULL);
2N/A
2N/A /*
2N/A * Skip stub nodes
2N/A */
2N/A if (IS_STUB_NODE(node)) {
2N/A return (DI_WALK_CONTINUE);
2N/A }
2N/A
2N/A errno = 0;
2N/A
2N/A drv = di_driver_name(node);
2N/A inst = di_instance(node);
2N/A physpath = di_devfs_path(node);
2N/A if (drv == NULL || inst == -1 || physpath == NULL) {
2N/A rv = DI_WALK_CONTINUE;
2N/A goto out;
2N/A }
2N/A
2N/A devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1;
2N/A
2N/A devpath = calloc(1, devlen);
2N/A drvinst = calloc(1, drvlen);
2N/A if (devpath == NULL || drvinst == NULL) {
2N/A dptp->l_errno = errno;
2N/A dptp->ret = SCFGA_LIB_ERR;
2N/A rv = DI_WALK_TERMINATE;
2N/A goto out;
2N/A }
2N/A
2N/A (void) snprintf(drvinst, drvlen, "%s%d", drv, inst);
2N/A
2N/A /* Create the physical path */
2N/A (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath);
2N/A
2N/A /* Skip node if it is the HBA */
2N/A match_minor = 0;
2N/A if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) {
2N/A rv = DI_WALK_CONTINUE;
2N/A goto out;
2N/A }
2N/A
2N/A /* Compare the base and dynamic components */
2N/A if (!hba_dev_cmp(dptp->hba_phys, devpath) &&
2N/A strcmp(dptp->dyncomp, drvinst) == 0) {
2N/A dptp->ret = SCFGA_OK;
2N/A dptp->path = devpath;
2N/A rv = DI_WALK_TERMINATE;
2N/A } else {
2N/A rv = DI_WALK_CONTINUE;
2N/A }
2N/A
2N/A /*FALLTHRU*/
2N/Aout:
2N/A S_FREE(drvinst);
2N/A if (physpath != NULL) di_devfs_path_free(physpath);
2N/A if (dptp->ret != SCFGA_OK) S_FREE(devpath);
2N/A return (rv);
2N/A}
2N/A
2N/A/* readlink wrapper to ensure proper null termination of the results */
2N/Astatic int
2N/As_readlink(char *link, char *buf, int len)
2N/A{
2N/A int count;
2N/A
2N/A count = readlink(link, buf, len - 1);
2N/A if (count != -1)
2N/A buf[count] = '\0';
2N/A return (count);
2N/A}
2N/A
2N/A/* Converts a devlink based dynamic component to a path */
2N/Astatic scfga_ret_t
2N/Adevlink_dyn_to_devpath(
2N/A const char *hba_phys,
2N/A const char *dyncomp,
2N/A char **pathpp,
2N/A int *l_errnop)
2N/A{
2N/A dyn_t dynt = {NULL};
2N/A int i;
2N/A scfga_ret_t ret;
2N/A char buf[PATH_MAX], *path;
2N/A
2N/A if (*pathpp != NULL) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A /* Convert the dynamic component to the corresponding devlink */
2N/A dynt.dyncomp = (char *)dyncomp;
2N/A dynt.ret = SCFGA_APID_NOEXIST;
2N/A
2N/A for (i = 0; i < N_DYNRULES; i++) {
2N/A if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt)
2N/A != SCFGA_CONTINUE) {
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (i >= N_DYNRULES) {
2N/A dynt.ret = SCFGA_APID_NOEXIST;
2N/A }
2N/A
2N/A if (dynt.ret != SCFGA_OK) {
2N/A /* No symlink or error */
2N/A return (dynt.ret);
2N/A }
2N/A
2N/A assert(dynt.devlink != NULL);
2N/A
2N/A /*
2N/A * Follow devlink to get the physical path
2N/A * Note: Do not use realpath(). It will stat() device
2N/A * and stat() fails under devfs if device is offline.
2N/A */
2N/A errno = 0;
2N/A if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) ||
2N/A ((path = strstr(buf, "/devices/")) == NULL) ||
2N/A ((*pathpp = strdup(path)) == NULL)) {
2N/A *l_errnop = errno;
2N/A ret = SCFGA_LIB_ERR;
2N/A goto out;
2N/A }
2N/A
2N/A /* Compare base components as well */
2N/A if (!hba_dev_cmp(hba_phys, path)) {
2N/A ret = SCFGA_OK;
2N/A } else {
2N/A /* Mismatched base and dynamic component */
2N/A *l_errnop = 0;
2N/A ret = SCFGA_APID_NOEXIST;
2N/A }
2N/A
2N/A /*FALLTHRU*/
2N/Aout:
2N/A S_FREE(dynt.devlink);
2N/A if (ret != SCFGA_OK) S_FREE(*pathpp);
2N/A return (ret);
2N/A}
2N/A
2N/Ascfga_ret_t
2N/Amake_dyncomp(
2N/A di_node_t node,
2N/A const char *physpath,
2N/A char **dyncompp,
2N/A int *l_errnop)
2N/A{
2N/A char *devlink = NULL;
2N/A scfga_ret_t ret;
2N/A di_minor_t minor;
2N/A char *path;
2N/A char pathbuf[MAXPATHLEN];
2N/A int match_minor;
2N/A
2N/A if (*dyncompp != NULL) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A /* tag on minor name */
2N/A minor = di_minor_next(node, DI_MINOR_NIL);
2N/A if (minor == DI_MINOR_NIL) {
2N/A match_minor = 0;
2N/A path = (char *)physpath;
2N/A } else {
2N/A match_minor = 1;
2N/A (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
2N/A di_minor_name(minor));
2N/A path = pathbuf;
2N/A }
2N/A
2N/A /* Get the corresponding devlink from the physical path */
2N/A ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor);
2N/A if (ret == SCFGA_OK) {
2N/A assert(devlink != NULL);
2N/A
2N/A /* Create dynamic component. */
2N/A ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop);
2N/A S_FREE(devlink);
2N/A if (ret == SCFGA_OK) {
2N/A assert(*dyncompp != NULL);
2N/A return (SCFGA_OK);
2N/A }
2N/A
2N/A /*
2N/A * Failed to get devlink based dynamic component.
2N/A * Try driver and instance
2N/A */
2N/A }
2N/A
2N/A ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop);
2N/A assert(ret != SCFGA_OK || *dyncompp != NULL);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Create a dynamic component of path ap_id for the given path info node.
2N/A * The caller should free the buffer for the dynamic component.
2N/A */
2N/Ascfga_ret_t
2N/Amake_path_dyncomp(
2N/A di_path_t path,
2N/A char **dyncompp,
2N/A int *l_errnop)
2N/A{
2N/A char *pi_addr;
2N/A
2N/A if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A if ((pi_addr = di_path_bus_addr(path)) != NULL) {
2N/A *dyncompp = calloc(1, strlen(pi_addr) + 1);
2N/A if (*dyncompp == NULL) {
2N/A *l_errnop = errno;
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A (void) strncpy(*dyncompp, pi_addr, strlen(pi_addr));
2N/A } else {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A return (SCFGA_OK);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic scfga_ret_t
2N/Adrv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop)
2N/A{
2N/A char *drv;
2N/A int inst;
2N/A const int dynlen = MAXPATHLEN;
2N/A scfga_ret_t ret;
2N/A
2N/A *l_errnop = 0;
2N/A
2N/A if ((*dyncompp = calloc(1, dynlen)) == NULL) {
2N/A *l_errnop = errno;
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A drv = di_driver_name(node);
2N/A inst = di_instance(node);
2N/A if (drv != NULL && inst != -1) {
2N/A if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) {
2N/A return (SCFGA_OK);
2N/A } else {
2N/A ret = SCFGA_LIB_ERR;
2N/A }
2N/A } else {
2N/A ret = SCFGA_APID_NOEXIST;
2N/A }
2N/A
2N/A S_FREE(*dyncompp);
2N/A return (ret);
2N/A}
2N/A
2N/A/* Get a dynamic component from a physical path if possible */
2N/Astatic scfga_ret_t
2N/Adevlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop)
2N/A{
2N/A int i;
2N/A dyn_t dynt = {NULL};
2N/A
2N/A *l_errnop = 0;
2N/A
2N/A if (*dyncompp != NULL) {
2N/A return (SCFGA_LIB_ERR);
2N/A }
2N/A
2N/A /* Convert devlink to dynamic component */
2N/A dynt.devlink = devlink;
2N/A dynt.ret = SCFGA_APID_NOEXIST;
2N/A
2N/A for (i = 0; i < N_DYNRULES; i++) {
2N/A if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt)
2N/A != SCFGA_CONTINUE) {
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (i >= N_DYNRULES) {
2N/A dynt.ret = SCFGA_APID_NOEXIST;
2N/A }
2N/A
2N/A if (dynt.ret == SCFGA_OK) {
2N/A assert(dynt.dyncomp != NULL);
2N/A *dyncompp = dynt.dyncomp;
2N/A }
2N/A
2N/A return (dynt.ret);
2N/A}
2N/A
2N/A/* For disks remove partition information, (s or p) */
2N/Astatic scfga_recur_t
2N/Adisk_devlink_to_dyncomp(dyn_t *dyntp)
2N/A{
2N/A char *cp = NULL, *cp1 = NULL;
2N/A
2N/A assert(dyntp->devlink != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->dyncomp != NULL) {
2N/A goto lib_err;
2N/A }
2N/A
2N/A /* Check if a disk devlink */
2N/A if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) &&
2N/A strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) {
2N/A return (SCFGA_CONTINUE);
2N/A }
2N/A
2N/A cp = dyntp->devlink + strlen(DEV_DIR SLASH);
2N/A
2N/A if ((dyntp->dyncomp = strdup(cp)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A goto lib_err;
2N/A }
2N/A
2N/A /* Get the leaf component from dsk/cXtYdZsN */
2N/A cp1 = strrchr(dyntp->dyncomp, '/');
2N/A
2N/A /* Blank out partition information */
2N/A dyntp->ret = SCFGA_OK;
2N/A if ((cp = strchr(cp1 + 1, 's')) != NULL) {
2N/A *cp = '\0';
2N/A } else if ((cp = strchr(cp1 + 1, 'p')) != NULL) {
2N/A *cp = '\0';
2N/A } else {
2N/A S_FREE(dyntp->dyncomp);
2N/A dyntp->ret = SCFGA_ERR;
2N/A }
2N/A
2N/A return (SCFGA_TERMINATE);
2N/A
2N/Alib_err:
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A}
2N/A
2N/A
2N/Astatic scfga_recur_t
2N/Adisk_dyncomp_to_devlink(dyn_t *dyntp)
2N/A{
2N/A char buf[MAXPATHLEN], *cp = NULL;
2N/A int i, j;
2N/A size_t len;
2N/A struct stat sbuf;
2N/A
2N/A assert(dyntp->dyncomp != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->devlink != NULL) {
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A
2N/A /* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */
2N/A if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0)
2N/A return (SCFGA_CONTINUE); /* not a disk link */
2N/A
2N/A (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
2N/A dyntp->dyncomp);
2N/A
2N/A len = strlen(buf);
2N/A cp = buf + len;
2N/A len = sizeof (buf) - len;
2N/A
2N/A for (i = 0; i < N_SLICE_TYPES; i++) {
2N/A for (j = 0; j < disk_slices[i].nslices; j++) {
2N/A if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j)
2N/A >= len) {
2N/A continue;
2N/A }
2N/A
2N/A if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
2N/A if ((dyntp->devlink = strdup(buf)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A dyntp->ret = SCFGA_OK;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A }
2N/A }
2N/A
2N/A dyntp->ret = SCFGA_APID_NOEXIST;
2N/A return (SCFGA_TERMINATE);
2N/A}
2N/A
2N/A/* For tapes, remove mode(minor) information from link */
2N/Astatic scfga_recur_t
2N/Atape_devlink_to_dyncomp(dyn_t *dyntp)
2N/A{
2N/A char *cp = NULL;
2N/A
2N/A assert(dyntp->devlink != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->dyncomp != NULL) {
2N/A goto lib_err;
2N/A }
2N/A
2N/A if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) {
2N/A return (SCFGA_CONTINUE); /* not a tape */
2N/A }
2N/A
2N/A cp = dyntp->devlink + strlen(DEV_DIR SLASH);
2N/A if ((dyntp->dyncomp = strdup(cp)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A goto lib_err;
2N/A }
2N/A
2N/A /* Get the leaf component from rmt/xyz */
2N/A cp = strrchr(dyntp->dyncomp, '/');
2N/A
2N/A /* Remove the mode part */
2N/A while (isdigit(*(++cp))) {
2N/A };
2N/A *cp = '\0';
2N/A
2N/A
2N/A dyntp->ret = SCFGA_OK;
2N/A return (SCFGA_TERMINATE);
2N/A
2N/Alib_err:
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A}
2N/A
2N/Astatic scfga_recur_t
2N/Atape_dyncomp_to_devlink(dyn_t *dyntp)
2N/A{
2N/A char buf[MAXPATHLEN], *cp = NULL;
2N/A int i;
2N/A size_t len = 0;
2N/A struct stat sbuf;
2N/A
2N/A assert(dyntp->dyncomp != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->devlink != NULL) {
2N/A goto lib_err;
2N/A }
2N/A
2N/A if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) {
2N/A return (SCFGA_CONTINUE); /* not a tape */
2N/A }
2N/A
2N/A /* A tape device */
2N/A (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
2N/A dyntp->dyncomp);
2N/A
2N/A len = strlen(buf);
2N/A cp = buf + len;
2N/A len = sizeof (buf) - len;
2N/A
2N/A for (i = 0; i < N_TAPE_MODES; i++) {
2N/A (void) snprintf(cp, len, "%s", tape_modes[i]);
2N/A
2N/A if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
2N/A if ((dyntp->devlink = strdup(buf)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A goto lib_err;
2N/A }
2N/A dyntp->ret = SCFGA_OK;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A }
2N/A
2N/A dyntp->ret = SCFGA_APID_NOEXIST;
2N/A return (SCFGA_TERMINATE);
2N/A
2N/Alib_err:
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Default rules
2N/A */
2N/Astatic scfga_recur_t
2N/Adef_devlink_to_dyncomp(dyn_t *dyntp)
2N/A{
2N/A size_t len = 0;
2N/A char *cp = NULL;
2N/A
2N/A assert(dyntp->devlink != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->dyncomp != NULL) {
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A
2N/A /* Is it a link in DEV_DIR directory ? */
2N/A len = strlen(DEV_DIR SLASH);
2N/A if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) {
2N/A return (SCFGA_CONTINUE);
2N/A }
2N/A
2N/A /* Check if this is a top level devlink */
2N/A if (strchr(dyntp->devlink + len, '/') != NULL) {
2N/A /* not top level - Remove DEV_DIR SLASH prefix */
2N/A cp = dyntp->devlink + len;
2N/A } else {
2N/A /* top level, leave DEV_DIR SLASH part in */
2N/A cp = dyntp->devlink;
2N/A }
2N/A
2N/A if ((dyntp->dyncomp = strdup(cp)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A } else {
2N/A dyntp->ret = SCFGA_OK;
2N/A }
2N/A
2N/A return (SCFGA_TERMINATE);
2N/A
2N/A}
2N/A
2N/Astatic scfga_recur_t
2N/Adef_dyncomp_to_devlink(dyn_t *dyntp)
2N/A{
2N/A struct stat sbuf;
2N/A int top;
2N/A size_t prelen, linklen;
2N/A
2N/A assert(dyntp->dyncomp != NULL);
2N/A
2N/A dyntp->l_errno = 0;
2N/A
2N/A if (dyntp->devlink != NULL) {
2N/A goto lib_err;
2N/A }
2N/A
2N/A prelen = strlen(DEV_DIR SLASH);
2N/A linklen = strlen(dyntp->dyncomp) + 1;
2N/A
2N/A /*
2N/A * Check if the dynamic component was derived from a top level entry
2N/A * in "/dev"
2N/A */
2N/A if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) {
2N/A top = 1;
2N/A } else if (*dyntp->dyncomp != '/' && linklen > 1 &&
2N/A strchr(dyntp->dyncomp + 1, '/') != NULL) {
2N/A top = 0;
2N/A linklen += prelen; /* The "/dev/" needs to be prepended */
2N/A } else {
2N/A /* Not a dynamic component we handle */
2N/A return (SCFGA_CONTINUE);
2N/A }
2N/A
2N/A if ((dyntp->devlink = calloc(1, linklen)) == NULL) {
2N/A dyntp->l_errno = errno;
2N/A goto lib_err;
2N/A }
2N/A
2N/A *dyntp->devlink = '\0';
2N/A if (!top) {
2N/A (void) strcpy(dyntp->devlink, DEV_DIR SLASH);
2N/A }
2N/A (void) strcat(dyntp->devlink, dyntp->dyncomp);
2N/A
2N/A if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
2N/A dyntp->ret = SCFGA_OK;
2N/A return (SCFGA_TERMINATE);
2N/A }
2N/A
2N/A
2N/A S_FREE(dyntp->devlink);
2N/A return (SCFGA_CONTINUE);
2N/A
2N/Alib_err:
2N/A dyntp->ret = SCFGA_LIB_ERR;
2N/A return (SCFGA_TERMINATE);
2N/A}