Sun Java Solaris Communities My SDN Account Join SDN
 
White Paper
libdevinfo Userland Access to Solaris Device Information
 
  « Previous | Contents | Next »
 

Programming Model


Taking a Snapshot

The kernel device tree is a dynamic entity. Device nodes might come and go as a result of driver module loading/unloading and user-initiated device reconfiguration. To obtain a consistent view of the device tree, libdevinfo locks the kernel device tree, takes a snapshot, and passes the snapshot data to user applications.

Back to Top


Using Handles

Applications access snapshot data through a set of opaque handles:

di_node_t Handle to a device node
di_prop_t Handle to a property
di_minor_t Handle to a minor node
di_prom_handle_t Handle to the PROM
di_prom_prop_t Handle to a property defined in the PROM

These handles are to be used as arguments to libdevinfo interfaces only; applications should not manipulate them directly. Note that properties defined in the PROM differ from other properties in that PROM properties persist across reboots.

     

Back to Top


Using libdevinfo

To use libdevinfo, follow these steps, which are described in detail in the sections below:

  1. Create a Snapshot of the Device Tree
  2. Traverse the Device Tree Snapshot
  3. Access Device Node Information
  4. Destroy the Snapshot

Create a Snapshot of the Device Tree

A snapshot of the device tree is created by calling di_init(3). The statement:

di_node_t root = di_init("/", DINFOCPYALL);

creates a snapshot of the device tree, which includes all information accessible through libdevinfo, which is not necessarily the same as what /devices exposes. The return value of di_init() is a handle to the root device node; using the handle, the application can access the information in the snapshot.

Control over what information to include in the snapshot is provided by the second argument to the function di_init(), which is a bitwise OR of the following fields:

DINFOPROP Include properties
DINFOMINOR Include minor nodes
DINFOSUBTREE Include all nodes in subtree
DINFOCPYALL Include all of the above (defined for convenience)

At minimum, applications can snapshot a single node with its attributes by specifying a physical path as the first argument and 0 as the second argument to di_init(). Applications can specify DINFOPROP, DINFOMINOR, DINFOSUBTREE, or a combination OR'ed together in the second argument. Specifying DINFOPROP will include properties; DINFOMINOR, minor node data; and DINFOSUBTREE, device nodes in the subtree rooted at the node specified by the first argument. DINFOCPYALL is defined for convenience; it is a bitwise OR of all three flags.

The physical path is a name space private to the Solaris DDI. Given a handle to a device node, the physical path can be obtained by calling di_devfs_path(3). The physical path to the root of the device tree is "/".

     

Back to Top

Traverse the Device Tree Snapshot

The device tree can be traversed through parent, child, and sibling linkage. Each device node contains references to its parent, its next sibling, and its first child. Given the root node handle returned from di_init(), applications can locate the root node's children by first calling di_child_node(3), and subsequently calling di_sibling_node(3), until DI_NODE_NIL is returned. By following this procedure recursively, applications can visit all device nodes contained in the snapshot. As an alternative to this, traversing the entire device tree is simplified by calling di_walk_node(3), which visits all device nodes in a snapshot and executes a caller-supplied function for each device node. The caller can specify depth-first or breadth-first walking order.

The device tree can also be traversed through per-driver linkage, which is an association of all nodes bound to the same device driver. This is done by calling di_drv_first_node(3), followed by successive calls to di_drv_next_node(3) until DI_NODE_NIL is returned. Note that traversing the per-driver device node list is allowed only when the snapshot includes all device nodes. If the snapshot does not contain all device nodes, the node selection can only be done by checking the driver name of every device node in the tree.

     

Back to Top

Access Device Node Information

There are three types of device node information:

  • Attributes
    • Given a handle to a libdevinfo node, call the corresponding interfaces listed in the di_node_name(3) man page to obtain attribute values. In addition, di_devfs_path(3) can be called to get the physical path to the device node.
  • Properties
      There are two ways to access properties:
    • To enumerate all properties of a device node, call di_prop_next(3) in succession until DI_PROP_NIL is returned; the caller now has handles to all properties. Given a property handle, call di_prop_name(3) and related interfaces to obtain the name and value of the property.
    • To look up the value of a property with a given name, call di_prop_lookup_ints(3) and related interfaces.

    Accessing PROM properties is similar except: the interface names start with di_prom_prop instead of di_prop and the caller must obtain a PROM handle by calling di_prom_init(3). Once the access is complete, di_prom_fini(3) should be called to free the PROM handle.

  • Minor node data
      There are also two ways to access minor nodes:
    • One way is to call di_minor_next(3).

    • The other way is to call di_walk_minor(3), which visits all minor nodes associated with each device node in a subtree and executes a caller supplied function for each minor node. di_walk_minor() combines the device node traversal with minor node traversal. Data associated with minor nodes are accessed through di_minor_name(3) and related interfaces.
     

Back to Top

Destroy the Snapshot

A snapshot is destroyed by calling:

di_fini(root);

where root is the handle returned from di_init(). Destroying a snapshot has the effect of freeing all memory associated with that snapshot and invalidating all associated handles. The application must ensure that invalidated handles are not referenced.

Back to Top


Header File and Compilation

Source files should include the libdevinfo.h header file:
#include <libdevinfo.h>

The application should be linked with libdevinfo using the -ldevinfo option:

cc program.c ... -ldevinfo

Back to Top


64-bit Implications

The 32-bit version of libdevinfo works on top of both the 64-bit and 32-bit Solaris kernels. This means that most device administration programs do not require conversion or recompilation to work with the 64-bit kernel. The only caveat is that when the representation of device number (dev_t) grows from 32-bit to 64-bit in the 64-bit kernel, the 32-bit libdevinfo will represent large device numbers (a major number greater than 14 bits or minor number greater than 18 bits) as NODEV. The relevant interfaces are di_prop_devt(3), di_minor_devt(3), and property lookup functions.

A 64-bit version of libdevinfo is also available for 64-bit applications.

     

Back to Top


Memory Management

The libdevinfo interfaces handle memory allocation and deallocation internally. The user must call the following interfaces in pairs to avoid memory leaks:

di_init()
di_fini()
Allocate and free memory for a snapshot
di_prom_init()
di_prom_fini()
Allocate and free memory for storing PROM properties
di_devfs_path()
di_devfs_path_free()
Allocate and free memory for storing the physical path to device nodes

Back to Top


Error Information

The libdevinfo interfaces indicate error conditions by setting the errno variable. Mapping of error codes to error conditions are described in the man pages. No error strings are passed to the caller or directed to any output. Here are the most common error codes:

  • EPERM

    The effective user ID lacks sufficient privilege to access device configuration data. root or sys privilege is required. The relevant interfaces are di_init() and di_prom_init(), both requiring root or sys privilege.

  • ENOMEM

    The system lacks sufficient memory to fulfill the request. The relevant interfaces are di_init(), di_prom_init(), and di_devfs_path().

  • ENXIO

    The requested information does not exist. This error code may be set by several interfaces.

  • ENOTSUP

    The requested information does not exist in the snapshot. This differs from ENXIO in that the caller is requesting information that was not included in the snapshot to begin with. In other words, ENOTSUP indicates a programming error.

     

Back to Top


Internationalization

The libdevinfo interfaces do not output any strings. These functions can be used by internationalized applications with no special modifications.

Back to Top


Limitations

The libdevinfo interfaces do not permit modification of device configuration data, and they do not provide the capability to track changes in the device configuration data. These limitations are by design to make the interfaces user-friendly.

  « Previous | Contents | Next »