4 * Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
7 #include "config-infocenter.h"
9 #include <QTreeWidgetItemIterator>
13 #include <sys/mnttab.h>
15 #include <sys/types.h>
16 #include <sys/statvfs.h>
19 #ifdef HAVE_LIBDEVINFO_H
23 #include <sys/mkdev.h>
26 #include <libdevinfo.h>
27 #endif /* HAVE_LIBDEVINFO_H */
29 bool GetInfo_CPU(QTreeWidget
* tree
) {
34 char cputype
[16], fputype
[16];
38 unsigned long state_begin
;
44 * get a kstat handle first and update the user's kstat chain
46 if ( (kctl
= kstat_open()) == NULL
) {
49 while (kstat_chain_update(kctl
) != 0)
55 if ( (ksp
= kstat_lookup(kctl
, "unix", 0, "system_misc")) == NULL
) {
58 if (kstat_read(kctl
, ksp
, NULL
) == -1) {
61 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "ncpus");
63 ncpus
= kdata
->value
.ui32
;
69 headers
<< i18n("Instance") << i18n("CPU Type") << i18n("FPU Type") << i18n("MHz") << i18n("State");
70 tree
->setHeaderLabels(headers
);
73 * get the per-processor info
75 for (i
= 0; i
< ncpus
; i
++) {
77 if ( (ksp
= kstat_lookup(kctl
, "cpu_info", i
, NULL
)) == NULL
) {
81 if (kstat_read(kctl
, ksp
, NULL
) == -1) {
86 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "cpu_type");
88 strcpy(cputype
, kdata
->value
.c
);
90 sprintf(cputype
, "???");
92 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "fpu_type");
94 strcpy(fputype
, kdata
->value
.c
);
96 sprintf(fputype
, "???");
98 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "clock_MHz");
100 mhz
.setNum(kdata
->value
.ul
);
104 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "state");
106 state
= QString(kdata
->value
.c
);
110 kdata
= (kstat_named_t
*) kstat_data_lookup(ksp
, "state_begin");
112 state_begin
= kdata
->value
.i32
;
113 if ( (timetxt
= ctime( (time_t *) &state_begin
)) != NULL
) {
114 ptr
= strrchr(timetxt
, '\n');
116 state
+= " since " + QString(timetxt
);
121 list
<< inst
<< cputype
<< fputype
<< mhz
<< state
;
122 new QTreeWidgetItem(tree
, list
);
125 tree
->sortItems(0, Qt::AscendingOrder
);
130 bool GetInfo_IRQ(QTreeWidget
*) {
134 bool GetInfo_DMA(QTreeWidget
*) {
138 bool GetInfo_PCI(QTreeWidget
*) {
142 bool GetInfo_IO_Ports(QTreeWidget
*) {
146 bool GetInfo_Sound(QTreeWidget
*) {
150 bool GetInfo_SCSI(QTreeWidget
*) {
154 bool GetInfo_Partitions(QTreeWidget
* tree
) {
158 struct statvfs statbuf
;
166 if ( (mnttab
= fopen(MNTTAB
, "r")) == NULL
) {
171 * set up column headers
174 headers
<< i18n("Device") << i18n("Mount Point") << i18n("FS Type") << i18n("Total Size") << i18n("Free Size") << i18n("Mount Time") << i18n("Mount Options");
175 tree
->setHeaderLabels(headers
);
177 // XXX: FIXME: how do I set column alignment correctly?
178 //tree->setColumnAlignment( 3, 2 );
179 // XXX: FIXME: how do I set column alignment correctly?
180 //tree->setColumnAlignment( 4, 2 );
183 * get info about mounted file systems
186 while (getmntent(mnttab
, &mnt
) == 0) {
188 * skip fstype "nfs" and "autofs" for two reasons:
189 * o if the mountpoint is visible, the fs is not
190 * necessarily available (autofs option "-nobrowse")
191 * and we don't want to mount every remote fs just
192 * to get its size, do we?
193 * o the name "Partitions" for this statistics implies
194 * "local file systems only"
196 if ( (strcmp(mnt
.mnt_fstype
, "nfs") == 0) || (strcmp(mnt
.mnt_fstype
, "autofs") == 0))
198 if (statvfs(mnt
.mnt_mountp
, &statbuf
) == 0) {
199 if (statbuf
.f_blocks
> 0) {
201 * produce output in KB, MB, or GB for
202 * readability -- unfortunately, this
203 * breaks sorting for these columns...
205 tmp
= statbuf
.f_blocks
* (statbuf
.f_frsize
/ 1024);
220 // avail.setNum( statbuf.f_bavail );
222 tmp
= statbuf
.f_bavail
* (statbuf
.f_frsize
/ 1024);
246 * ctime() adds a '\n' which we have to remove
247 * so that we get a one-line output for the QTreeWidgetItem
249 mnttime
= (time_t) atol(mnt
.mnt_time
);
250 if ( (timetxt
= ctime( &mnttime
)) != NULL
) {
251 ptr
= strrchr(timetxt
, '\n');
256 list
<< mnt
.mnt_special
<< mnt
.mnt_mountp
<< mnt
.mnt_fstype
<< total
<< avail
<< QString(timetxt
) << mnt
.mnt_mntopts
;
257 new QTreeWidgetItem(tree
, list
);
261 tree
->sortItems(0, Qt::AscendingOrder
);
266 bool GetInfo_XServer_and_Video(QTreeWidget
* tree
) {
267 return GetInfo_XServer_Generic(tree
);
270 #ifdef HAVE_LIBDEVINFO_H
272 * get Solaris' device configuration data through libdevinfo(3)
273 * and display it in a prtconf(1M) style tree
275 * NOTE: though the devinfo library seems to be present on earlier
276 * Solaris releases, this interface is documented to be available
277 * since Solaris 7 (libdevinfo.h is missing on pre-Solaris 7 systems)
279 * documentation for libdevinfo(3) including code samples on which
280 * this implementation is based on is available at
281 * http://soldc.sun.com/developer/support/driver/wps/libdevinfo/
285 * we start with various helper routines for GetInfo_Devices()
289 * mktree() -- break up the device path and place its components
290 * into the tree widget
292 QTreeWidgetItem
* mktree( QTreeWidgetItem
* top
, const char* path
) {
294 QTreeWidgetItem
* parent
;
295 QTreeWidgetItem
* previous
;
296 QTreeWidgetItem
* result
;
297 char* str
= strdup( path
);
304 result
= top
->child(0);
305 previous
= top
->child(0);
307 token
= strtok( str
, "/" );
308 while( token
!= NULL
) {
311 * try to match the node at the current level
313 * NOTE: this implementation assumes that there are
314 * no two nodes with identical names at the
315 * same level of the device tree
317 QTreeWidgetItemIterator
it(top
, QTreeWidgetItemIterator::All
);
318 while ( *it
!= NULL
) {
319 if( strcmp( token
, (*it
)->text( 0 ).toLatin1()) == 0 )
327 if( result
== NULL
) {
332 * we haven't found the node, create a new one
334 result
= new QTreeWidgetItem(parent
, previous
, list
);
338 * we've found the node
342 if( result
->child(0) == NULL
) {
344 * create new node during next iteration
346 result
->setExpanded(false);
349 * follow the child path
351 result
= result
->child(0);
354 token
= strtok( NULL
, "/" );
363 * prop_type_str() -- return the property type as a string
365 char *prop_type_str( di_prop_t prop
) {
367 switch( di_prop_type( prop
)) {
368 case DI_PROP_TYPE_UNDEF_IT
:
369 return( "undefined" );
370 case DI_PROP_TYPE_BOOLEAN
:
372 case DI_PROP_TYPE_INT
:
374 case DI_PROP_TYPE_STRING
:
376 case DI_PROP_TYPE_BYTE
:
384 * prop_type_guess() -- guess the property type
386 int prop_type_guess( uchar_t
*data
, int len
) {
395 return( DI_PROP_TYPE_BOOLEAN
);
398 guess
= DI_PROP_TYPE_STRING
;
400 for( i
= 0; i
< len
; i
++ ) {
407 guess
= DI_PROP_TYPE_BYTE
;
413 guess
= DI_PROP_TYPE_BYTE
;
417 if( guess
!= DI_PROP_TYPE_STRING
)
421 // if( (guess == DI_PROP_TYPE_BYTE) && (len % sizeof( int ) == 0 ))
422 // guess = DI_PROP_TYPE_INT;
428 * dump_minor_node() -- examine a device minor node
429 * this routine gets passed to di_walk_node()
431 int dump_minor_node( di_node_t node
, di_minor_t minor
, void *arg
) {
438 list
<< di_minor_name( minor
);
439 QTreeWidgetItem
* item
= new QTreeWidgetItem( (QTreeWidgetItem
*) arg
, list
);
440 item
->setExpanded(false);
443 if (di_minor_spectype( minor
) == S_IFCHR
)
444 specResult
= i18n( "character special" );
446 specResult
= i18n( "block special" );
449 spec
<< i18n( "Spectype:" ) << specResult
;
451 new QTreeWidgetItem(item
, spec
);
453 type
= di_minor_nodetype( minor
);
462 node
<< i18n( "Nodetype:" ) << nodeResult
;
464 new QTreeWidgetItem(item
, node
);
466 if( (dev
= di_minor_devt( minor
)) != DDI_DEV_T_NONE
) {
467 majmin
.sprintf( "%ld/%ld", major( dev
), minor( dev
));
469 mn
<< i18n( "Major/Minor:" ) << majmin
;
470 new QTreeWidgetItem(item
, mn
);
473 if( di_minor_next( node
, minor
) == DI_MINOR_NIL
)
474 return DI_WALK_TERMINATE
;
476 return DI_WALK_CONTINUE
;
480 * propvalue() -- return the property value
482 QString
propvalue( di_prop_t prop
) {
492 * Since a lot of printable strings seem to be tagged as 'byte',
493 * we're going to guess, if the property is not STRING or INT
494 * The actual type is shown in the info tree, though.
496 type
= di_prop_type( prop
);
497 if( (type
!= DI_PROP_TYPE_STRING
) && (type
!= DI_PROP_TYPE_INT
) ) {
498 n
= di_prop_bytes( prop
, &bytep
);
499 type
= prop_type_guess( bytep
, n
);
504 case DI_PROP_TYPE_STRING
:
505 if( (n
= di_prop_strings( prop
, &strp
)) < 0 ) {
508 for( i
= 0; i
< n
; i
++ ) {
512 strp
+= strlen( strp
) + 1;
516 case DI_PROP_TYPE_INT
:
517 if( (n
= di_prop_ints( prop
, &intp
)) < 0 ) {
520 for( i
= 0; i
< n
; i
++ ) {
522 tmp
.setNum( intp
[i
] );
528 case DI_PROP_TYPE_BOOLEAN
:
530 * hmm, Sun's sample code handles the existence
531 * of a boolean property as "true", whereas
532 * prtconf(1M) obviously does not (Sol8, at least)
533 * -- we're doing the same and handle "bool" as "byte"
535 case DI_PROP_TYPE_BYTE
:
536 if( (n
= di_prop_bytes( prop
, &bytep
)) < 0 ) {
540 result
= i18n( "(no value)" );
544 for( i
= 0; i
< n
; i
++ ) {
546 unsigned byte
= (unsigned) bytep
[i
];
547 tmp
.sprintf( "%2.2x", byte
);
560 * dump_node() -- examine a device node and its children
561 * this routine gets passed to di_walk_node()
563 int dump_node( di_node_t node
, void *arg
) {
565 QTreeWidgetItem
*top
= (QTreeWidgetItem
*) arg
;
566 QTreeWidgetItem
*parent
;
574 path
= di_devfs_path( node
);
577 * if this is the root node ("/"), initialize the tree
579 if( strlen( path
) == 1 ) {
580 top
->setText( 0, QString( di_binding_name( node
)));
581 top
->setIcon( 0, SmallIcon( "kcmdevices" ));
582 top
->setExpanded( true );
586 * place the node in the tree
588 parent
= mktree( top
, path
);
591 * we have to handle the root node differently...
593 if( strlen( path
) > 1 ) {
594 parent
->setExpanded(false);
600 * node name and physical device path
602 drivername
= di_driver_name( node
);
604 QStringList driverList
;
605 driverList
<< i18n( "Driver Name:" );
606 if (drivername
==NULL
)
607 driverList
<< i18n( "(driver not attached)" );
609 driverList
<< drivername
;
611 new QTreeWidgetItem(parent
, driverList
);
613 QStringList bindingList
;
614 bindingList
<< i18n( "Binding Name:" ) << di_binding_name( node
);
615 new QTreeWidgetItem(parent
, bindingList
);
617 n
= di_compatible_names( node
, &names
);
619 compatnames
= i18n( "(none)" );
621 for( i
= 0; i
< n
; i
++ ) {
622 compatnames
+= names
;
624 names
+= strlen( names
) + 1;
628 QStringList compatibleList
;
629 compatibleList
<< i18n( "Compatible Names:" ) << compatnames
;
630 new QTreeWidgetItem(parent
, compatibleList
);
632 QStringList physicalList
;
633 physicalList
<< i18n( "Physical Path:" ) << QString( path
);
634 new QTreeWidgetItem(parent
, physicalList
);
637 * dump the node's property list (if any)
639 if( (prop
= di_prop_next( node
, DI_PROP_NIL
)) != DI_PROP_NIL
) {
641 QTreeWidgetItem
*previous
;
642 QStringList propertiesList
;
643 propertiesList
<< i18n( "Properties" );
644 previous
= new QTreeWidgetItem(parent
, propertiesList
);
645 previous
->setExpanded( false );
649 * property type & value
651 QStringList propList
;
652 propList
<< di_prop_name( prop
);
653 QTreeWidgetItem
* tmp
= new QTreeWidgetItem(previous
, propList
);
654 tmp
->setExpanded( false );
656 QStringList typeList
;
657 typeList
<< i18n( "Type:" ) << prop_type_str( prop
);
658 new QTreeWidgetItem( tmp
, typeList
);
660 QStringList valueList
;
661 valueList
<< i18n( "Value:" ) << propvalue( prop
);
662 new QTreeWidgetItem( tmp
, valueList
);
664 }while( (prop
= di_prop_next( node
, prop
)) != DI_PROP_NIL
);
668 * if there are minor nodes, expand the tree appropriately
670 if( di_minor_next( node
, DI_MINOR_NIL
) != DI_MINOR_NIL
) {
671 QStringList minorList
;
672 minorList
<< i18n( "Minor Nodes" );
673 QTreeWidgetItem
* previous
= new QTreeWidgetItem(parent
, minorList
);
674 previous
->setExpanded(false);
675 di_walk_minor( node
, NULL
, 0, previous
, dump_minor_node
);
678 return DI_WALK_CONTINUE
;
681 bool GetInfo_Devices( QTreeWidget
* tree
) {
686 * create a snapshot of the device tree
688 if( (root_node
= di_init( "/", DINFOCPYALL
)) == DI_NODE_NIL
) {
691 // XXX: might try to di_prom_init() here as well (if we're setgid sys)
694 * prepare the tree widget
697 headers
<< i18n( "Device Information" ) << i18n( "Value" );
698 tree
->setHeaderLabels(headers
);
700 QTreeWidgetItem
* top
= new QTreeWidgetItem( tree
);
703 * traverse the device tree
705 di_walk_node( root_node
, DI_WALK_CLDFIRST
, top
, dump_node
);
707 di_fini( root_node
);
709 tree
->setSortingEnabled(false);
714 #else /* ! HAVE_LIBDEVINFO_H */
715 bool GetInfo_Devices(QTreeWidget
*) {
718 #endif /* ! HAVE_LIBDEVINFO_H */