diff options
Diffstat (limited to 'kcontrol/info/info_solaris.cpp')
-rw-r--r-- | kcontrol/info/info_solaris.cpp | 705 |
1 files changed, 705 insertions, 0 deletions
diff --git a/kcontrol/info/info_solaris.cpp b/kcontrol/info/info_solaris.cpp new file mode 100644 index 000000000..761200e75 --- /dev/null +++ b/kcontrol/info/info_solaris.cpp @@ -0,0 +1,705 @@ +/* + * info_solaris.cpp + * + * Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/mnttab.h> +#include <kstat.h> +#include <sys/types.h> +#include <sys/statvfs.h> +#include <time.h> + +#ifdef HAVE_LIBDEVINFO_H +#include <ctype.h> +#include <string.h> +#include <unistd.h> +#include <sys/mkdev.h> +#include <sys/stat.h> +#include <devid.h> +#include <libdevinfo.h> +#endif /* HAVE_LIBDEVINFO_H */ + +#define INFO_CPU_AVAILABLE +#define INFO_IRQ_AVAILABLE +#define INFO_DMA_AVAILABLE +#define INFO_PCI_AVAILABLE +#define INFO_IOPORTS_AVAILABLE +#define INFO_SOUND_AVAILABLE +#define INFO_DEVICES_AVAILABLE +#define INFO_SCSI_AVAILABLE +#define INFO_PARTITIONS_AVAILABLE +#define INFO_XSERVER_AVAILABLE + + +bool GetInfo_CPU( QListView *lBox ) { + + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; + char cputype[16], + fputype[16]; + char *timetxt; + char *ptr; + uint32_t i, ncpus; + unsigned long state_begin; + QString state; + QString mhz; + QString inst; + + /* + * get a kstat handle first and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) { + return false; + } + while( kstat_chain_update( kctl ) != 0 ) + ; + + /* + * get the # of CPUs + */ + if( (ksp = kstat_lookup( kctl, "unix", 0, "system_misc" )) == NULL ) { + return false; + } + if( kstat_read( kctl, ksp, NULL ) == -1 ) { + return false; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ncpus" ); + if( kdata != NULL ) { + ncpus = kdata->value.ui32; + } else { + ncpus = 0; + } + + lBox->addColumn( i18n( "Instance" )); + lBox->addColumn( i18n( "CPU Type" )); + lBox->addColumn( i18n( "FPU Type" )); + lBox->addColumn( i18n( "MHz" )); + lBox->addColumn( i18n( "State" )); + + /* + * get the per-processor info + */ + for( i = 0; i < ncpus; i++ ) { + + if( (ksp = kstat_lookup( kctl, "cpu_info", i, NULL )) == NULL ){ + return false; + } + + if( kstat_read( kctl, ksp, NULL ) == -1 ) { + return false; + } + + inst.setNum( i ); + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_type" ); + if( kdata != NULL ) { + strcpy( cputype, kdata->value.c ); + } else { + sprintf( cputype, "???" ); + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "fpu_type" ); + if( kdata != NULL ) { + strcpy( fputype, kdata->value.c ); + } else { + sprintf( fputype, "???" ); + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "clock_MHz" ); + if( kdata != NULL ) { + mhz.setNum( kdata->value.ul ); + } else { + mhz.setNum( 0 ); + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "state" ); + if( kdata != NULL ) { + state = QString( kdata->value.c ); + } else { + state = "???"; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "state_begin" ); + if( kdata != NULL ) { + state_begin = kdata->value.i32; + if( (timetxt = ctime( (time_t *) &state_begin )) != NULL ) { + ptr = strrchr( timetxt, '\n' ); + *ptr = '\0'; + state += " since " + QString( timetxt ); + } + } + + new QListViewItem( lBox, inst, cputype, fputype, mhz, state ); + } + + // sorting_allowed = true; + lBox->setSorting( 0 ); + + return true; +} + +bool GetInfo_IRQ( QListView * ) { + return false; +} + +bool GetInfo_DMA( QListView * ) { + return false; +} + +bool GetInfo_PCI( QListView * ) { + return false; +} + +bool GetInfo_IO_Ports( QListView * ) { + return false; +} + +bool GetInfo_Sound( QListView * ) { + return false; +} + +bool GetInfo_SCSI( QListView * ) { + return false; +} + +bool GetInfo_Partitions( QListView *lBox ) { + + FILE *mnttab; + struct mnttab mnt; + struct statvfs statbuf; + fsblkcnt_t tmp; + QString total; + QString avail; + time_t mnttime; + char *timetxt; + char *ptr; + + if( (mnttab = fopen( MNTTAB, "r" )) == NULL ) { + return false; + } + + /* + * set up column headers + */ + lBox->addColumn( i18n( "Device" )); + lBox->addColumn( i18n( "Mount Point" )); + lBox->addColumn( i18n( "FS Type" )); + lBox->addColumn( i18n( "Total Size" )); + // XXX: FIXME: how do I set column alignment correctly? + lBox->setColumnAlignment( 3, 2 ); + lBox->addColumn( i18n( "Free Size" )); + // XXX: FIXME: how do I set column alignment correctly? + lBox->setColumnAlignment( 4, 2 ); + lBox->addColumn( i18n( "Mount Time" )); + lBox->addColumn( i18n( "Mount Options" )); + + /* + * get info about mounted file systems + */ + rewind( mnttab ); + while( getmntent( mnttab, &mnt ) == 0 ) { + /* + * skip fstype "nfs" and "autofs" for two reasons: + * o if the mountpoint is visible, the fs is not + * necessarily available (autofs option "-nobrowse") + * and we don't want to mount every remote fs just + * to get its size, do we? + * o the name "Partitions" for this statistics implies + * "local file systems only" + */ + if( (strcmp( mnt.mnt_fstype, "nfs" ) == 0) + || (strcmp( mnt.mnt_fstype, "autofs" ) == 0) ) + continue; + if( statvfs( mnt.mnt_mountp, &statbuf ) == 0 ) { + if( statbuf.f_blocks > 0 ) { + /* + * produce output in KB, MB, or GB for + * readability -- unfortunately, this + * breaks sorting for these columns... + */ + tmp = statbuf.f_blocks + * (statbuf.f_frsize / 1024); + if( tmp > 9999 ) { + tmp /= 1024; + if( tmp > 9999 ) { + tmp /= 1024; + total.setNum( tmp ); + total += " G"; + } else { + total.setNum( tmp ); + total += " M"; + } + } else { + total.setNum( tmp ); + total += " K"; + } +// avail.setNum( statbuf.f_bavail ); +// avail += " K"; + tmp = statbuf.f_bavail + * (statbuf.f_frsize / 1024); + if( tmp > 9999 ) { + tmp /= 1024; + if( tmp > 9999 ) { + tmp /= 1024; + avail.setNum( tmp ); + avail += " G"; + } else { + avail.setNum( tmp ); + avail += " M"; + } + } else { + avail.setNum( tmp ); + avail += " K"; + } + } else { + total = "-"; + avail = "-"; + } + } else { + total = "???"; + avail = "???"; + } + /* + * ctime() adds a '\n' which we have to remove + * so that we get a one-line output for the QListViewItem + */ + mnttime = (time_t) atol( mnt.mnt_time ); + if( (timetxt = ctime( &mnttime )) != NULL ) { + ptr = strrchr( timetxt, '\n' ); + *ptr = '\0'; + } + + new QListViewItem( + lBox, + mnt.mnt_special, + mnt.mnt_mountp, + mnt.mnt_fstype, + total, + avail, + QString( timetxt ), + mnt.mnt_mntopts + ); + } + fclose( mnttab ); + + lBox->setSorting( 0 ); + // sorting_allowed = true; + + return true; +} + +bool GetInfo_XServer_and_Video( QListView *lBox ) { + return GetInfo_XServer_Generic( lBox ); +} + +#ifdef HAVE_LIBDEVINFO_H +/* + * get Solaris' device configuration data through libdevinfo(3) + * and display it in a prtconf(1M) style tree + * + * NOTE: though the devinfo library seems to be present on earlier + * Solaris releases, this interface is documented to be available + * since Solaris 7 (libdevinfo.h is missing on pre-Solaris 7 systems) + * + * documentation for libdevinfo(3) including code samples on which + * this implementation is based on is available at + * http://soldc.sun.com/developer/support/driver/wps/libdevinfo/ + */ + +/* + * we start with various helper routines for GetInfo_Devices() + */ + +/* + * mktree() -- break up the device path and place its components + * into the tree widget + */ +QListViewItem *mktree( QListViewItem *top, const char *path ) { + + QListViewItem *parent, + *previous, + *result; + char *str = strdup( path ), + *token; + + /* + * start at "/" + */ + parent = top; + result = (*top).firstChild(); + previous = (*top).firstChild(); + + token = strtok( str, "/" ); + while( token != NULL ) { + /* + * find insert pos: + * try to match the node at the current level + * + * NOTE: this implementation assumes that there are + * no two nodes with identical names at the + * same level of the device tree + */ + while( result != NULL ) { + if( strcmp( token, (*result).text( 0 ).latin1()) == 0 ) + break; + previous = result; + result = (*result).nextSibling(); + } + if( result == NULL ) { + /* + * we haven't found the node, create a new one + */ + result = new QListViewItem( parent, + previous, + token ); + } else { + /* + * we've found the node + */ + parent = result; + previous = NULL; + if( (*result).firstChild() == NULL ) { + /* + * create new node during next iteration + */ + result->setExpandable( true ); + result->setOpen( false ); + } else { + /* + * follow the child path + */ + result = (*result).firstChild(); + } + } + token = strtok( NULL, "/" ); + } + free( str ); + + return( result ); +} + +/* + * prop_type_str() -- return the property type as a string + */ +char *prop_type_str( di_prop_t prop ) { + + switch( di_prop_type( prop )) { + case DI_PROP_TYPE_UNDEF_IT: + return( "undefined" ); + 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" ); + } +} + +/* + * prop_type_guess() -- guess the property type + */ +int prop_type_guess( uchar_t *data, int len ) { + + int slen; + int guess; + int i, c; + + 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: + if( i == (len - 1 )) + break; + if( slen == 0 ) + guess = DI_PROP_TYPE_BYTE; + else + guess = 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 ); +} + +/* + * dump_minor_node() -- examine a device minor node + * this routine gets passed to di_walk_node() + */ +int dump_minor_node( di_node_t node, di_minor_t minor, void *arg ) { + + QListViewItem *item; + QString majmin; + char *type; + dev_t dev; + + item = new QListViewItem( (QListViewItem *) arg, + di_minor_name( minor )); + item->setExpandable( true ); + item->setOpen( false ); + new QListViewItem( item, i18n( "Spectype:" ), + (di_minor_spectype( minor ) == S_IFCHR) + ? i18n( "character special" ) + : i18n( "block special" )); + type = di_minor_nodetype( minor ); + new QListViewItem( item, i18n( "Nodetype:" ), + (type == NULL) ? "NULL" : type ); + + if( (dev = di_minor_devt( minor )) != DDI_DEV_T_NONE ) { + majmin.sprintf( "%ld/%ld", major( dev ), minor( dev )); + new QListViewItem( item, i18n( "Major/Minor:" ), majmin ); + } + + if( di_minor_next( node, minor ) == DI_MINOR_NIL ) + return( DI_WALK_TERMINATE ); + else + return( DI_WALK_CONTINUE ); +} + +/* + * propvalue() -- return the property value + */ +QString propvalue( di_prop_t prop ) { + + int type; + int i, n; + char *strp; + int *intp; + uchar_t *bytep; + QString result; + + /* + * Since a lot of printable strings seem to be tagged as 'byte', + * we're going to guess, if the property is not STRING or INT + * The actual type is shown in the info tree, though. + */ + type = di_prop_type( prop ); + if( (type != DI_PROP_TYPE_STRING) && (type != DI_PROP_TYPE_INT) ) { + n = di_prop_bytes( prop, &bytep ); + type = prop_type_guess( bytep, n ); + } + + result = ""; + switch( type ) { + case DI_PROP_TYPE_STRING: + if( (n = di_prop_strings( prop, &strp )) < 0 ) { + result = "(error)"; + } else { + for( i = 0; i < n; i++ ) { + result += "\""; + result += strp; + result += "\" "; + strp += strlen( strp ) + 1; + } + } + break; + case DI_PROP_TYPE_INT: + if( (n = di_prop_ints( prop, &intp )) < 0 ) { + result = "(error)"; + } else { + for( i = 0; i < n; i++ ) { + QString tmp; + tmp.setNum( intp[i] ); + result += tmp; + result += " "; + } + } + break; + case DI_PROP_TYPE_BOOLEAN: + /* + * hmm, Sun's sample code handles the existence + * of a boolean property as "true", whereas + * prtconf(1M) obviously does not (Sol8, at least) + * -- we're doing the same and handle "bool" as "byte" + */ + case DI_PROP_TYPE_BYTE: + if( (n = di_prop_bytes( prop, &bytep )) < 0 ) { + result = "(error)"; + } else { + if( n == 0 ) { + result = i18n( "(no value)" ); + break; + } + result = "0x"; + for( i = 0; i < n; i++ ) { + QString tmp; + unsigned byte = (unsigned) bytep[i]; + tmp.sprintf( "%2.2x", byte ); + result += tmp; + } + } + break; + default: + result = "???"; + } + + return( result ); +} + +/* + * dump_node() -- examine a device node and its children + * this routine gets passed to di_walk_node() + */ +int dump_node( di_node_t node, void *arg ) { + + QListViewItem *top = (QListViewItem *) arg, + *parent, + *previous; + char *path; + char *drivername; + char *names; + QString compatnames; + int i, n; + di_prop_t prop; + + path = di_devfs_path( node ); + + /* + * if this is the root node ("/"), initialize the tree + */ + if( strlen( path ) == 1 ) { + top->setText( 0, QString( di_binding_name( node ))); + top->setPixmap( 0, SmallIcon( "kcmdevices" )); + top->setOpen( true ); + top->setSelectable( false ); + top->setExpandable( false ); + } + + /* + * place the node in the tree + */ + parent = mktree( top, path ); + + /* + * we have to handle the root node differently... + */ + if( strlen( path ) > 1 ) { + parent->setExpandable( true ); + parent->setOpen( false ); + } else { + previous = parent; + parent = top; + } + + /* + * node name and physical device path + */ + drivername = di_driver_name( node ); + previous = new QListViewItem( parent, + i18n( "Driver Name:" ), + (drivername == NULL) + ? i18n( "(driver not attached)" ) + : drivername ); + previous = new QListViewItem( parent, previous, + i18n( "Binding Name:" ), di_binding_name( node )); + + n = di_compatible_names( node, &names ); + if( n < 1 ) { + compatnames = i18n( "(none)" ); + } else { + for( i = 0; i < n; i++ ) { + compatnames += names; + compatnames += " "; + names += strlen( names ) + 1; + } + } + + previous = new QListViewItem( parent, previous, + i18n( "Compatible Names:" ), compatnames ); + + previous = new QListViewItem( parent, previous, + i18n( "Physical Path:" ), QString( path )); + + /* + * dump the node's property list (if any) + */ + if( (prop = di_prop_next( node, DI_PROP_NIL )) != DI_PROP_NIL ) { + previous = new QListViewItem( parent, previous, i18n( "Properties" )); + previous->setExpandable( true ); + previous->setOpen( false ); + do { + /* + * property type & value + */ + QListViewItem *tmp, + *prev; + tmp = new QListViewItem( previous, di_prop_name( prop )); + tmp->setExpandable( true ); + tmp->setOpen( false ); + prev = new QListViewItem( tmp, i18n( "Type:" ), + prop_type_str( prop )); + new QListViewItem( tmp, prev, i18n( "Value:" ), + propvalue( prop )); + } while( (prop = di_prop_next( node, prop )) != DI_PROP_NIL ); + } + + /* + * if there are minor nodes, expand the tree appropriately + */ + if( di_minor_next( node, DI_MINOR_NIL ) != DI_MINOR_NIL ) { + previous = new QListViewItem( parent, previous, i18n( "Minor Nodes" )); + previous->setExpandable( true ); + previous->setOpen( false ); + di_walk_minor( node, NULL, 0, previous, dump_minor_node ); + } + + return( DI_WALK_CONTINUE ); +} + +bool GetInfo_Devices( QListView *lBox ) { + + QListViewItem *top; + di_node_t root_node; + + /* + * create a snapshot of the device tree + */ + if( (root_node = di_init( "/", DINFOCPYALL )) == DI_NODE_NIL ) { + return( false ); + } + // XXX: might try to di_prom_init() here as well (if we're setgid sys) + + /* + * prepare the tree widget + */ + lBox->addColumn( i18n( "Device Information" )); + lBox->addColumn( i18n( "Value" )); + + top = new QListViewItem( lBox ); + + /* + * traverse the device tree + */ + di_walk_node( root_node, DI_WALK_CLDFIRST, top, dump_node ); + + di_fini( root_node ); + + sorting_allowed = false; + return true; +} + +#else /* ! HAVE_LIBDEVINFO_H */ +bool GetInfo_Devices( QListView * ) { + return false; +} +#endif /* ! HAVE_LIBDEVINFO_H */ |