4 * Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
7 #include "config-infocenter.h"
11 #include <sys/mnttab.h>
13 #include <sys/types.h>
14 #include <sys/statvfs.h>
17 #ifdef HAVE_LIBDEVINFO_H
21 #include <sys/mkdev.h>
24 #include <libdevinfo.h>
25 #endif /* HAVE_LIBDEVINFO_H */
27 #define INFO_CPU_AVAILABLE
28 #define INFO_IRQ_AVAILABLE
29 #define INFO_DMA_AVAILABLE
30 #define INFO_PCI_AVAILABLE
31 #define INFO_IOPORTS_AVAILABLE
32 #define INFO_SOUND_AVAILABLE
33 #define INFO_DEVICES_AVAILABLE
34 #define INFO_SCSI_AVAILABLE
35 #define INFO_PARTITIONS_AVAILABLE
36 #define INFO_XSERVER_AVAILABLE
39 bool GetInfo_CPU( Q3ListView
*lBox
) {
49 unsigned long state_begin
;
55 * get a kstat handle first and update the user's kstat chain
57 if( (kctl
= kstat_open()) == NULL
) {
60 while( kstat_chain_update( kctl
) != 0 )
66 if( (ksp
= kstat_lookup( kctl
, "unix", 0, "system_misc" )) == NULL
) {
69 if( kstat_read( kctl
, ksp
, NULL
) == -1 ) {
72 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "ncpus" );
74 ncpus
= kdata
->value
.ui32
;
79 lBox
->addColumn( i18n( "Instance" ));
80 lBox
->addColumn( i18n( "CPU Type" ));
81 lBox
->addColumn( i18n( "FPU Type" ));
82 lBox
->addColumn( i18n( "MHz" ));
83 lBox
->addColumn( i18n( "State" ));
86 * get the per-processor info
88 for( i
= 0; i
< ncpus
; i
++ ) {
90 if( (ksp
= kstat_lookup( kctl
, "cpu_info", i
, NULL
)) == NULL
){
94 if( kstat_read( kctl
, ksp
, NULL
) == -1 ) {
99 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "cpu_type" );
100 if( kdata
!= NULL
) {
101 strcpy( cputype
, kdata
->value
.c
);
103 sprintf( cputype
, "???" );
105 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "fpu_type" );
106 if( kdata
!= NULL
) {
107 strcpy( fputype
, kdata
->value
.c
);
109 sprintf( fputype
, "???" );
111 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "clock_MHz" );
112 if( kdata
!= NULL
) {
113 mhz
.setNum( kdata
->value
.ul
);
117 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "state" );
118 if( kdata
!= NULL
) {
119 state
= QString( kdata
->value
.c
);
123 kdata
= (kstat_named_t
*) kstat_data_lookup( ksp
, "state_begin" );
124 if( kdata
!= NULL
) {
125 state_begin
= kdata
->value
.i32
;
126 if( (timetxt
= ctime( (time_t *) &state_begin
)) != NULL
) {
127 ptr
= strrchr( timetxt
, '\n' );
129 state
+= " since " + QString( timetxt
);
133 new Q3ListViewItem( lBox
, inst
, cputype
, fputype
, mhz
, state
);
136 // sorting_allowed = true;
137 lBox
->setSorting( 0 );
142 bool GetInfo_IRQ( Q3ListView
* ) {
146 bool GetInfo_DMA( Q3ListView
* ) {
150 bool GetInfo_PCI( Q3ListView
* ) {
154 bool GetInfo_IO_Ports( Q3ListView
* ) {
158 bool GetInfo_Sound( Q3ListView
* ) {
162 bool GetInfo_SCSI( Q3ListView
* ) {
166 bool GetInfo_Partitions( Q3ListView
*lBox
) {
170 struct statvfs statbuf
;
178 if( (mnttab
= fopen( MNTTAB
, "r" )) == NULL
) {
183 * set up column headers
185 lBox
->addColumn( i18n( "Device" ));
186 lBox
->addColumn( i18n( "Mount Point" ));
187 lBox
->addColumn( i18n( "FS Type" ));
188 lBox
->addColumn( i18n( "Total Size" ));
189 // XXX: FIXME: how do I set column alignment correctly?
190 lBox
->setColumnAlignment( 3, 2 );
191 lBox
->addColumn( i18n( "Free Size" ));
192 // XXX: FIXME: how do I set column alignment correctly?
193 lBox
->setColumnAlignment( 4, 2 );
194 lBox
->addColumn( i18n( "Mount Time" ));
195 lBox
->addColumn( i18n( "Mount Options" ));
198 * get info about mounted file systems
201 while( getmntent( mnttab
, &mnt
) == 0 ) {
203 * skip fstype "nfs" and "autofs" for two reasons:
204 * o if the mountpoint is visible, the fs is not
205 * necessarily available (autofs option "-nobrowse")
206 * and we don't want to mount every remote fs just
207 * to get its size, do we?
208 * o the name "Partitions" for this statistics implies
209 * "local file systems only"
211 if( (strcmp( mnt
.mnt_fstype
, "nfs" ) == 0)
212 || (strcmp( mnt
.mnt_fstype
, "autofs" ) == 0) )
214 if( statvfs( mnt
.mnt_mountp
, &statbuf
) == 0 ) {
215 if( statbuf
.f_blocks
> 0 ) {
217 * produce output in KB, MB, or GB for
218 * readability -- unfortunately, this
219 * breaks sorting for these columns...
221 tmp
= statbuf
.f_blocks
222 * (statbuf
.f_frsize
/ 1024);
237 // avail.setNum( statbuf.f_bavail );
239 tmp
= statbuf
.f_bavail
240 * (statbuf
.f_frsize
/ 1024);
264 * ctime() adds a '\n' which we have to remove
265 * so that we get a one-line output for the Q3ListViewItem
267 mnttime
= (time_t) atol( mnt
.mnt_time
);
268 if( (timetxt
= ctime( &mnttime
)) != NULL
) {
269 ptr
= strrchr( timetxt
, '\n' );
286 lBox
->setSorting( 0 );
287 // sorting_allowed = true;
292 bool GetInfo_XServer_and_Video( Q3ListView
*lBox
) {
293 return GetInfo_XServer_Generic( lBox
);
296 #ifdef HAVE_LIBDEVINFO_H
298 * get Solaris' device configuration data through libdevinfo(3)
299 * and display it in a prtconf(1M) style tree
301 * NOTE: though the devinfo library seems to be present on earlier
302 * Solaris releases, this interface is documented to be available
303 * since Solaris 7 (libdevinfo.h is missing on pre-Solaris 7 systems)
305 * documentation for libdevinfo(3) including code samples on which
306 * this implementation is based on is available at
307 * http://soldc.sun.com/developer/support/driver/wps/libdevinfo/
311 * we start with various helper routines for GetInfo_Devices()
315 * mktree() -- break up the device path and place its components
316 * into the tree widget
318 Q3ListViewItem
*mktree( Q3ListViewItem
*top
, const char *path
) {
320 Q3ListViewItem
*parent
,
323 char *str
= strdup( path
),
330 result
= (*top
).firstChild();
331 previous
= (*top
).firstChild();
333 token
= strtok( str
, "/" );
334 while( token
!= NULL
) {
337 * try to match the node at the current level
339 * NOTE: this implementation assumes that there are
340 * no two nodes with identical names at the
341 * same level of the device tree
343 while( result
!= NULL
) {
344 if( strcmp( token
, (*result
).text( 0 ).toLatin1()) == 0 )
347 result
= (*result
).nextSibling();
349 if( result
== NULL
) {
351 * we haven't found the node, create a new one
353 result
= new Q3ListViewItem( parent
,
358 * we've found the node
362 if( (*result
).firstChild() == NULL
) {
364 * create new node during next iteration
366 result
->setExpandable( true );
367 result
->setOpen( false );
370 * follow the child path
372 result
= (*result
).firstChild();
375 token
= strtok( NULL
, "/" );
383 * prop_type_str() -- return the property type as a string
385 char *prop_type_str( di_prop_t prop
) {
387 switch( di_prop_type( prop
)) {
388 case DI_PROP_TYPE_UNDEF_IT
:
389 return( "undefined" );
390 case DI_PROP_TYPE_BOOLEAN
:
392 case DI_PROP_TYPE_INT
:
394 case DI_PROP_TYPE_STRING
:
396 case DI_PROP_TYPE_BYTE
:
404 * prop_type_guess() -- guess the property type
406 int prop_type_guess( uchar_t
*data
, int len
) {
415 return( DI_PROP_TYPE_BOOLEAN
);
418 guess
= DI_PROP_TYPE_STRING
;
420 for( i
= 0; i
< len
; i
++ ) {
427 guess
= DI_PROP_TYPE_BYTE
;
433 guess
= DI_PROP_TYPE_BYTE
;
437 if( guess
!= DI_PROP_TYPE_STRING
)
441 // if( (guess == DI_PROP_TYPE_BYTE) && (len % sizeof( int ) == 0 ))
442 // guess = DI_PROP_TYPE_INT;
448 * dump_minor_node() -- examine a device minor node
449 * this routine gets passed to di_walk_node()
451 int dump_minor_node( di_node_t node
, di_minor_t minor
, void *arg
) {
453 Q3ListViewItem
*item
;
458 item
= new Q3ListViewItem( (Q3ListViewItem
*) arg
,
459 di_minor_name( minor
));
460 item
->setExpandable( true );
461 item
->setOpen( false );
462 new Q3ListViewItem( item
, i18n( "Spectype:" ),
463 (di_minor_spectype( minor
) == S_IFCHR
)
464 ? i18n( "character special" )
465 : i18n( "block special" ));
466 type
= di_minor_nodetype( minor
);
467 new Q3ListViewItem( item
, i18n( "Nodetype:" ),
468 (type
== NULL
) ? "NULL" : type
);
470 if( (dev
= di_minor_devt( minor
)) != DDI_DEV_T_NONE
) {
471 majmin
.sprintf( "%ld/%ld", major( dev
), minor( dev
));
472 new Q3ListViewItem( item
, i18n( "Major/Minor:" ), majmin
);
475 if( di_minor_next( node
, minor
) == DI_MINOR_NIL
)
476 return( DI_WALK_TERMINATE
);
478 return( DI_WALK_CONTINUE
);
482 * propvalue() -- return the property value
484 QString
propvalue( di_prop_t prop
) {
494 * Since a lot of printable strings seem to be tagged as 'byte',
495 * we're going to guess, if the property is not STRING or INT
496 * The actual type is shown in the info tree, though.
498 type
= di_prop_type( prop
);
499 if( (type
!= DI_PROP_TYPE_STRING
) && (type
!= DI_PROP_TYPE_INT
) ) {
500 n
= di_prop_bytes( prop
, &bytep
);
501 type
= prop_type_guess( bytep
, n
);
506 case DI_PROP_TYPE_STRING
:
507 if( (n
= di_prop_strings( prop
, &strp
)) < 0 ) {
510 for( i
= 0; i
< n
; i
++ ) {
514 strp
+= strlen( strp
) + 1;
518 case DI_PROP_TYPE_INT
:
519 if( (n
= di_prop_ints( prop
, &intp
)) < 0 ) {
522 for( i
= 0; i
< n
; i
++ ) {
524 tmp
.setNum( intp
[i
] );
530 case DI_PROP_TYPE_BOOLEAN
:
532 * hmm, Sun's sample code handles the existence
533 * of a boolean property as "true", whereas
534 * prtconf(1M) obviously does not (Sol8, at least)
535 * -- we're doing the same and handle "bool" as "byte"
537 case DI_PROP_TYPE_BYTE
:
538 if( (n
= di_prop_bytes( prop
, &bytep
)) < 0 ) {
542 result
= i18n( "(no value)" );
546 for( i
= 0; i
< n
; i
++ ) {
548 unsigned byte
= (unsigned) bytep
[i
];
549 tmp
.sprintf( "%2.2x", byte
);
562 * dump_node() -- examine a device node and its children
563 * this routine gets passed to di_walk_node()
565 int dump_node( di_node_t node
, void *arg
) {
567 Q3ListViewItem
*top
= (Q3ListViewItem
*) arg
,
577 path
= di_devfs_path( node
);
580 * if this is the root node ("/"), initialize the tree
582 if( strlen( path
) == 1 ) {
583 top
->setText( 0, QString( di_binding_name( node
)));
584 top
->setPixmap( 0, SmallIcon( "kcmdevices" ));
585 top
->setOpen( true );
586 top
->setSelectable( false );
587 top
->setExpandable( false );
591 * place the node in the tree
593 parent
= mktree( top
, path
);
596 * we have to handle the root node differently...
598 if( strlen( path
) > 1 ) {
599 parent
->setExpandable( true );
600 parent
->setOpen( false );
607 * node name and physical device path
609 drivername
= di_driver_name( node
);
610 previous
= new Q3ListViewItem( parent
,
611 i18n( "Driver Name:" ),
613 ? i18n( "(driver not attached)" )
615 previous
= new Q3ListViewItem( parent
, previous
,
616 i18n( "Binding Name:" ), di_binding_name( node
));
618 n
= di_compatible_names( node
, &names
);
620 compatnames
= i18n( "(none)" );
622 for( i
= 0; i
< n
; i
++ ) {
623 compatnames
+= names
;
625 names
+= strlen( names
) + 1;
629 previous
= new Q3ListViewItem( parent
, previous
,
630 i18n( "Compatible Names:" ), compatnames
);
632 previous
= new Q3ListViewItem( parent
, previous
,
633 i18n( "Physical Path:" ), QString( path
));
636 * dump the node's property list (if any)
638 if( (prop
= di_prop_next( node
, DI_PROP_NIL
)) != DI_PROP_NIL
) {
639 previous
= new Q3ListViewItem( parent
, previous
, i18n( "Properties" ));
640 previous
->setExpandable( true );
641 previous
->setOpen( false );
644 * property type & value
648 tmp
= new Q3ListViewItem( previous
, di_prop_name( prop
));
649 tmp
->setExpandable( true );
650 tmp
->setOpen( false );
651 prev
= new Q3ListViewItem( tmp
, i18n( "Type:" ),
652 prop_type_str( prop
));
653 new Q3ListViewItem( tmp
, prev
, i18n( "Value:" ),
655 } while( (prop
= di_prop_next( node
, prop
)) != DI_PROP_NIL
);
659 * if there are minor nodes, expand the tree appropriately
661 if( di_minor_next( node
, DI_MINOR_NIL
) != DI_MINOR_NIL
) {
662 previous
= new Q3ListViewItem( parent
, previous
, i18n( "Minor Nodes" ));
663 previous
->setExpandable( true );
664 previous
->setOpen( false );
665 di_walk_minor( node
, NULL
, 0, previous
, dump_minor_node
);
668 return( DI_WALK_CONTINUE
);
671 bool GetInfo_Devices( Q3ListView
*lBox
) {
677 * create a snapshot of the device tree
679 if( (root_node
= di_init( "/", DINFOCPYALL
)) == DI_NODE_NIL
) {
682 // XXX: might try to di_prom_init() here as well (if we're setgid sys)
685 * prepare the tree widget
687 lBox
->addColumn( i18n( "Device Information" ));
688 lBox
->addColumn( i18n( "Value" ));
690 top
= new Q3ListViewItem( lBox
);
693 * traverse the device tree
695 di_walk_node( root_node
, DI_WALK_CLDFIRST
, top
, dump_node
);
697 di_fini( root_node
);
699 sorting_allowed
= false;
703 #else /* ! HAVE_LIBDEVINFO_H */
704 bool GetInfo_Devices( Q3ListView
* ) {
707 #endif /* ! HAVE_LIBDEVINFO_H */