You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kcontrol/info/info_solaris.cpp

706 lines
16 KiB

/*
* 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( TQListView *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 = TQString( 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 " + TQString( timetxt );
}
}
new TQListViewItem( lBox, inst, cputype, fputype, mhz, state );
}
// sorting_allowed = true;
lBox->setSorting( 0 );
return true;
}
bool GetInfo_IRQ( TQListView * ) {
return false;
}
bool GetInfo_DMA( TQListView * ) {
return false;
}
bool GetInfo_PCI( TQListView * ) {
return false;
}
bool GetInfo_IO_Ports( TQListView * ) {
return false;
}
bool GetInfo_Sound( TQListView * ) {
return false;
}
bool GetInfo_SCSI( TQListView * ) {
return false;
}
bool GetInfo_Partitions( TQListView *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 TQListViewItem(
lBox,
mnt.mnt_special,
mnt.mnt_mountp,
mnt.mnt_fstype,
total,
avail,
TQString( timetxt ),
mnt.mnt_mntopts
);
}
fclose( mnttab );
lBox->setSorting( 0 );
// sorting_allowed = true;
return true;
}
bool GetInfo_XServer_and_Video( TQListView *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
*/
TQListViewItem *mktree( TQListViewItem *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 TQListViewItem( 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 TQListViewItem( (TQListViewItem *) arg,
di_minor_name( minor ));
item->setExpandable( true );
item->setOpen( false );
new TQListViewItem( item, i18n( "Spectype:" ),
(di_minor_spectype( minor ) == S_IFCHR)
? i18n( "character special" )
: i18n( "block special" ));
type = di_minor_nodetype( minor );
new TQListViewItem( 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 TQListViewItem( 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
*/
TQString 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++ ) {
TQString 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++ ) {
TQString 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 = (TQListViewItem *) 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, TQString( 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 TQListViewItem( parent,
i18n( "Driver Name:" ),
(drivername == NULL)
? i18n( "(driver not attached)" )
: drivername );
previous = new TQListViewItem( 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 TQListViewItem( parent, previous,
i18n( "Compatible Names:" ), compatnames );
previous = new TQListViewItem( parent, previous,
i18n( "Physical Path:" ), TQString( path ));
/*
* dump the node's property list (if any)
*/
if( (prop = di_prop_next( node, DI_PROP_NIL )) != DI_PROP_NIL ) {
previous = new TQListViewItem( parent, previous, i18n( "Properties" ));
previous->setExpandable( true );
previous->setOpen( false );
do {
/*
* property type & value
*/
QListViewItem *tmp,
*prev;
tmp = new TQListViewItem( previous, di_prop_name( prop ));
tmp->setExpandable( true );
tmp->setOpen( false );
prev = new TQListViewItem( tmp, i18n( "Type:" ),
prop_type_str( prop ));
new TQListViewItem( 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 TQListViewItem( 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( TQListView *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 TQListViewItem( 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( TQListView * ) {
return false;
}
#endif /* ! HAVE_LIBDEVINFO_H */