Sun Java Solaris Communities My SDN Account Join SDN
 
White Paper
libdevinfo Userland Access to Solaris Device Information
  « Previous | Contents | Next »
 
Code Examples
The following three code examples illustrate how libdevinfo interfaces are used. Code Examples 1 and 2 show how to walk all device nodes and per-driver nodes. Code Example 3 produces a prtconf() style listing of all device configuration data. 
 
Example 1
Example 2
Example 3
 
CODE EXAMPLE 1 Print Node Names (example1.c) 
 
/*
 * Copyright 1994-2004 Sun Microsystems, Inc.
 * All Rights Reserved.
 */

/*
 * Print node names of all device nodes
 */
#include <stdio.h>
#include <libdevinfo.h>

/*ARGSUSED*/
static int
prt_nodename(di_node_t node, void *arg)
{
    (void) printf("%sn", di_node_name(node));
    return (DI_WALK_CONTINUE);
}

void
main(void)
{
    di_node_t root_node;
    extern void exit();

    if ((root_node = di_init("/", DINFOSUBTREE)) == DI_NODE_NIL) {
        perror("di_init() failedn");
        exit(1);
    }
    /*
     * Walk device tree in child-first order and print node name
     */
    (void) di_walk_node(root_node, DI_WALK_CLDFIRST, NULL, prt_nodename);
    di_fini(root_node);
}
 
[TOP]
 
CODE EXAMPLE 2 Print Physical Path of Disks (example2.c) 
 
/*
 * Copyright 1994-2004 Sun Microsystems, Inc.
 * All Rights Reserved.
 */

/*
 * Print physical path to disk nodes bound to the sd driver
 */
#include <stdio.h>
#include <libdevinfo.h>

#defineDISK_DRIVER"sd"

static void
prt_diskinfo(di_node_t node)
{
    int instance;
    char *phys_path;

    /*
     * If the device node exports no minor nodes,
     * there is no physical device.
     */
    if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL) {
        return;
    }

    instance = di_instance(node);
    phys_path = di_devfs_path(node);
    (void) printf("%s%d: %sn", DISK_DRIVER, instance, phys_path);
    di_devfs_path_free(phys_path);
}

static void
walk_disknodes(di_node_t node)
{
    node = di_drv_first_node(DISK_DRIVER, node);
    while (node != DI_NODE_NIL) {
        prt_diskinfo(node);
        node = di_drv_next_node(node);
    }
}

void
main(void)
{
    di_node_t root_node;
    extern void exit();

    if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
        perror("di_init() failed");
        exit(1);
    }
    walk_disknodes(root_node);
    di_fini(root_node);
}
 
[TOP]
 
CODE EXAMPLE 3 Listing All Device Information (example3.c) 
 
/*
 * Copyright 1994-2004 Sun Microsystems, Inc.
 * All Rights Reserved.
 */


/*
 * Print all device configuration information on the system
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/mkdev.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <devid.h>
#include <libdevinfo.h>

/*
 * local data
 */
static char *progname;
static char *usage = "%s [ -p ]n";
static int promprops = 0;       /* switch for prom properties */

/*
 * function declarations
 */
extern void exit();

static void setprogname(char *name);
static void dump_devinfo();
static int dump_node(di_node_t node, void *arg);
static void dump_prop_list(di_node_t node);
static void dump_prom_prop_list(di_node_t node, di_prom_handle_t ph);
static int dump_minor_node(di_node_t node, di_minor_t minor, void *arg);

/*
 * Formatting functions
 */
static void indent(int);
static void prt_strings(int, char *);
static void prt_nodeid(di_node_t);
static void prt_devid(di_node_t);
static void prt_driver_ops(di_node_t);
static void prt_devt(dev_t);
static char *prop_type_str(di_prop_t);
static int prop_type_guess(uchar_t *, int);

void
main(int argc, char *argv[])
{
        int     c;
        extern void exit();

        setprogname(argv[0]);
        while ((c = getopt(argc, argv, "p")) != -1)  {
                switch (c)  {
                case 'p':
                        ++promprops;
                        break;
                default:
                        (void) fprintf(stderr, usage, progname);
                        exit(1);
                }
        }

        dump_devinfo();
} /* main */


.
static void
setprogname(name)
char *name;
{
        char *p;

        if (p = strrchr(name, '/'))
                progname = p + 1;
        else
                progname = name;
}

/*
 * Call most libdevinfo public interfaces and print results
 */
static void
dump_devinfo(void)
{
        di_node_t root_node;
        di_prom_handle_t ph;

        /*
         * Snapshot with all information
         */
        if((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
                perror("di_init() failed");
                exit(1);
        }

        /*
         * Create handle to PROM
         */
        if(promprops && (ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
                perror("di_prom_init() failed");
                di_fini(root_node);
                exit (1);
        }

        /*
         * Walk all nodes and report information in readable format
         */
        di_walk_node(root_node, DI_WALK_CLDFIRST, ph, dump_node);

        /*
         * Clean up handles
         */
        if (promprops)
                di_prom_fini(ph);

        di_fini(root_node);
}

/*
 * print out information about this node, returns appropriate code.
 * arg is used to pass the handle to PROM
 */
static int
dump_node(di_node_t node, void *arg)
{
        int i;
        char *name;
        di_prom_handle_t ph = (di_prom_handle_t)arg;

        /*
         * print physical path, no indentation
         */
        name = di_devfs_path(node);
        (void) printf("%sn", name);
        di_devfs_path_free(name);

        /*
         * Print attributes with indentation
         */
        indent(1);
        (void) printf("compatible names: ");
        i = di_compatible_names(node, &name);
        prt_strings(i, name);

        indent(1);
        (void) printf("binding name: ");
        prt_strings(1, di_binding_name(node));

        indent(1);
        (void) printf("driver name: ");
        prt_strings(1, di_driver_name(node));

        prt_driver_ops(node);
        prt_nodeid(node);
        prt_devid(node);

        /*
         * Print properties
         */
        dump_prop_list(node);

        if (promprops)
                dump_prom_prop_list(node, ph);

        /*
         * Print minor node information
         */
        indent(1);
        (void) printf("Minor nodes:n");
        if(di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL) {
                indent(2);
                (void) printf("nonen");
        } else {
                /*
                 * Print minor nodes attached to this node
                 *
                 * Note, normally di_walk_minor() visit all minor nodes
                 * in the subtree. A trick is used here to walk only
                 * those minor node exported by the current node.
                 */
                (void) di_walk_minor(node, NULL, 0,
                        (void *)node, dump_minor_node);
        }

        return (DI_WALK_CONTINUE);
}
 
/*
 * Print properties associated with node
 */
static void
dump_prop_list(di_node_t node)
{
        int rval, i, type;
        di_prop_t prop, next;
        int *intp;
        char *strp;
        uchar_t *bytep;

        indent(1);
        (void) printf("Properties:n");

        if((next = di_prop_next(node, DI_PROP_NIL)) == DI_PROP_NIL) {
                indent(2);
                (void) printf("nonen");
                return;
        }

        while (next != DI_PROP_NIL) {
                prop = next;
                next = di_prop_next(node, prop);
                
                indent(2);
                (void) printf("name=%s, ", di_prop_name(prop));
                prt_devt(di_prop_devt(prop));
                (void) printf(", type=%sn", prop_type_str(prop));

                indent(2);
                (void) printf("value=");

                type = di_prop_type(prop);
                if (type == DI_PROP_TYPE_UNKNOWN) {
                        rval = di_prop_bytes(prop, &bytep);
                        type = prop_type_guess(bytep, rval);
                }

                switch (type) {
                case DI_PROP_TYPE_UNDEF_IT:
                        (void) printf(" undefined.");
                        break;
                case DI_PROP_TYPE_BOOLEAN:
                        (void) printf(" true.");
                        break;
                case DI_PROP_TYPE_INT:
                        rval = di_prop_ints(prop, &intp);
                        if (rval == -1) {
                                perror("di_prop_ints");
                                break;
                        }
                        for (i = 0; i < rval; ++i)
                                (void) printf(" %d", intp[i]);
                        break;
                case DI_PROP_TYPE_STRING:
                        rval = di_prop_strings(prop, &strp);
                        if (rval == -1) {
                                perror("di_prop_strings");
                                break;
                        }
                        for (i = 0; i < rval; ++i)  {
                                (void) printf(" "%s"", strp);
                                strp += strlen(strp) + 1;
                        }
                        break;
                case DI_PROP_TYPE_BYTE:
                        rval = di_prop_bytes(prop, &bytep);
                        if (rval == -1) {
                                perror("di_prop_bytes");
                                break;
                        }
                        (void) printf("0x");
                        for (i = 0; i < rval; ++i)  {
                                unsigned byte;
                                byte = (unsigned)bytep[i];
                                (void) printf("%2.2x", byte);
                        }
                        break;
                default:
                        (void) fprintf(stderr,
                            " Error: unknown property typen");
                }
                (void) printf("n");
        }
}

/*
 * Print PROM properties attached to node.
 * PROM properties are not typed
 */
static void
dump_prom_prop_list(di_node_t node, di_prom_handle_t ph)
{
        int rval, i, type;
        di_prom_prop_t prop;
        int *intp;
        char *strp;
        uchar_t *bytep;

        indent(1);
        (void) printf("PROM properties:n");

        if((prop = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL))
            == DI_PROM_PROP_NIL) {
                indent(2);
                (void) printf("nonen");
                return;
        }

        while (prop != DI_PROM_PROP_NIL) {
                
                rval = di_prom_prop_data(prop, &bytep);
                /*
                 * Try to guess a type so the value is more readable
                 */
                type = prop_type_guess(bytep, rval);

                indent(2);
                (void) printf("%s:", di_prom_prop_name(prop));

                switch (type) {
                case DI_PROP_TYPE_BOOLEAN:
                        (void) printf(" true.");
                        break;
                case DI_PROP_TYPE_INT:
                        /*
                         * lookup interfaces provide decoding (byte-order)
                         */
                        rval = di_prom_prop_lookup_ints(ph, node,
                                di_prom_prop_name(prop), &intp);
                        if (rval == -1) {
                                perror("di_prom_prop_lookup_ints");
                                break;
                        }
                        for (i = 0; i < rval; ++i)
                                (void) printf(" %d", intp[i]);
                        break;
                case DI_PROP_TYPE_STRING:
                        rval = di_prom_prop_lookup_strings(ph, node,
                                di_prom_prop_name(prop), &strp);
                        if (rval == -1) {
                                perror("di_prom_prop_lookup_strings");
                                break;
                        }
                        for (i = 0; i < rval; ++i)  {
                                (void) printf(" "%s"", strp);
                                strp += strlen(strp) + 1;
                        }
                        break;
                case DI_PROP_TYPE_BYTE:
                        rval = di_prom_prop_lookup_bytes(ph, node,
                                di_prom_prop_name(prop), &bytep);
                        if (rval == -1) {
                                perror("di_prom_prop_lookup_bytes");
                                break;
                        }
                        (void) printf("0x");
                        for (i = 0; i < rval; ++i)  {
                                unsigned byte;
                                byte = (unsigned)bytep[i];
                                (void) printf("%2.2x", byte);
                        }
                        break;
                default:
                        (void) fprintf(stderr,
                            "Error: unexpected type in dump_prom_prop_listn");
                }
                (void) printf("n");
                prop = di_prom_prop_next(ph, node, prop);
        }
}

/*
 * Print minor nodes attached to a single device node.
 * Terminate walk when the device node changes
 */
static int
dump_minor_node(di_node_t node, di_minor_t minor, void *arg)
{
        char *type;

        if ((caddr_t)node != (caddr_t)arg)
                return (DI_WALK_TERMINATE);

        indent(2);
        (void) printf("name=%s, ", di_minor_name(minor));

        prt_devt(di_minor_devt(minor));

        type = (di_minor_spectype(minor) == S_IFCHR) ? "char" : "block";
        (void) printf(", spectype=%s, ", type);

        type = di_minor_nodetype(minor);
        if (type)
                (void) printf("nodetype=%sn", type);
        else
                (void) printf("nodetype=NULLn");

        return (DI_WALK_CONTINUE);
}

static void
prt_strings(int n, char *strs)
{
        if ((n == 0) || (strs == NULL)) {
                (void) printf("nonen");
                return;
        }

        if (n == 1) {
                (void) printf("%sn", strs);
                return;
        }

        while (n) {
                (void) printf(" "%s"", strs);
                strs += strlen(strs) + 1;
                n--;
        }
        (void) printf("n");
}

static void
prt_nodeid(di_node_t node)
{
        indent(1);
        (void) printf("nodeid: ");

        switch (di_nodeid(node)) {
        case DI_PROM_NODEID:
                (void) printf("DI_PROM_NODEIDn");
                break;
        case DI_SID_NODEID:
                (void) printf("DI_SID_NODEIDn");
                break;
        case DI_PSEUDO_NODEID:
                (void) printf("DI_PSEUDO_NODEIDn");
                break;
        default:
                (void) printf("unknownn");
        }
}

static void
prt_driver_ops(di_node_t node)
{
        uint_t ops = di_driver_ops(node);

        indent(1);
        (void) printf("driver ops: ");

        if (ops == 0) {
                (void) printf("nonen");
                return;
        }

        if (ops & DI_BUS_OPS) {
                (void) printf("DI_BUS_OPS ");
        }
        if (ops & DI_CB_OPS) {
                (void) printf("DI_CB_OPS ");
        }
        if (ops & DI_STREAM_OPS) {
                (void) printf("DI_STREAM_OPS");
        }
        (void) printf("n");
}

static void
prt_devid(di_node_t node)
{
        int i, len;
        ddi_devid_t devid = di_devid(node);
        struct impl_devid *id = (struct impl_devid *)devid;

        indent(1);
        (void) printf("device id: ");
        if (id == NULL) {
                (void) printf("nonen");
                return;
        }

        (void) printf(" magic 0x%2.2x%2.2x",
            id->did_magic_hi, id->did_magic_lo);
        (void) printf(" revision 0x%2.2x%2.2x", id->did_rev_hi, id->did_rev_lo);
        (void) printf(" type 0x%2.2x%2.2x", id->did_type_hi, id->did_type_lo);
        (void) printf(" len 0x%2.2x%2.2xn", id->did_len_hi, id->did_len_lo);
        indent(1);
        (void) printf("    hint ");
        for(i = 0; (i < DEVID_HINT_SIZE) && id->did_driver[i]; i++)
                (void) putchar(id->did_driver[i]);

        (void) printf(" id 0x");
        len = (id->did_len_hi << 8) + id->did_len_lo;
        for(i = 0; i < len; i++)
                (void) printf("%2.2x", id->did_id[i]);
        (void) putchar('n');
}

static void
prt_devt(dev_t dev)
{
        if (dev == DDI_DEV_T_NONE) {
                (void) printf("dev=NONE");
        } else {
                (void) printf("dev=(%ld/%ld)", major(dev), minor(dev));
        }
}

static char *
prop_type_str(di_prop_t prop)
{
        switch (di_prop_type(prop)) {
        case DI_PROP_TYPE_UNDEF_IT:
                return ("UNDEF");
        case DI_PROP_TYPE_BOOLEAN:
                return ("BOOL");
        case DI_PROP_TYPE_INT:
                return ("INT");
        case DI_PROP_TYPE_STRING:
                return ("STRING");
        case DI_PROP_TYPE_BYTE:
                return ("BYTE");
        default:
                return ("UNKNOWN");
        }
        /* NOTREACHED */
}

/*
 * The guessing algorithm is:
 *      1. If every byte is printable, then its a string property
 *      2. Otherwise, if length is multiple of 4, its an interger property
 *      3. Otherwise, it's a byte array.
 */
static int
prop_type_guess(uchar_t *data, int len)
{
        int i, c, slen, guess;

        if (len < 0)
                return (-1);
        else if (len == 0)
                return (DI_PROP_TYPE_BOOLEAN);

        slen = 0;
        guess = DI_PROP_TYPE_STRING;

        for (i = 0; i < len; i++) {
                c = (int)data[i];
                switch (c) {
                case 0: /* null character */
                        if (slen == 0)
                                guess = DI_PROP_TYPE_BYTE;
                        else
                                slen = 0;
                        break;
                default:
                        if (! isprint(c))
                                guess = DI_PROP_TYPE_BYTE;
                        else
                                slen++;
                }

                if (guess != DI_PROP_TYPE_STRING)
                        break;
        }
                
        if ((guess == DI_PROP_TYPE_BYTE) && (len % sizeof(int) == 0))
                guess = DI_PROP_TYPE_INT;

        return (guess);
}

static void
indent(int n)
{
        const char *indent_string = "    ";

        while (n--) {
                (void) printf("%s", indent_string);
        }
}