Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / apps / kinfocenter / info / info_solaris.cpp
blob8e1e98a92f6c613e5f18cedb09c20bd4f0846251
1 /*
2 * info_solaris.cpp
4 * Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
5 */
7 #include "config-infocenter.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/mnttab.h>
12 #include <kstat.h>
13 #include <sys/types.h>
14 #include <sys/statvfs.h>
15 #include <time.h>
17 #ifdef HAVE_LIBDEVINFO_H
18 #include <ctype.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/mkdev.h>
22 #include <sys/stat.h>
23 #include <devid.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 ) {
41 kstat_ctl_t *kctl;
42 kstat_t *ksp;
43 kstat_named_t *kdata;
44 char cputype[16],
45 fputype[16];
46 char *timetxt;
47 char *ptr;
48 uint32_t i, ncpus;
49 unsigned long state_begin;
50 QString state;
51 QString mhz;
52 QString inst;
55 * get a kstat handle first and update the user's kstat chain
57 if( (kctl = kstat_open()) == NULL ) {
58 return false;
60 while( kstat_chain_update( kctl ) != 0 )
64 * get the # of CPUs
66 if( (ksp = kstat_lookup( kctl, "unix", 0, "system_misc" )) == NULL ) {
67 return false;
69 if( kstat_read( kctl, ksp, NULL ) == -1 ) {
70 return false;
72 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ncpus" );
73 if( kdata != NULL ) {
74 ncpus = kdata->value.ui32;
75 } else {
76 ncpus = 0;
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 ){
91 return false;
94 if( kstat_read( kctl, ksp, NULL ) == -1 ) {
95 return false;
98 inst.setNum( i );
99 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_type" );
100 if( kdata != NULL ) {
101 strcpy( cputype, kdata->value.c );
102 } else {
103 sprintf( cputype, "???" );
105 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "fpu_type" );
106 if( kdata != NULL ) {
107 strcpy( fputype, kdata->value.c );
108 } else {
109 sprintf( fputype, "???" );
111 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "clock_MHz" );
112 if( kdata != NULL ) {
113 mhz.setNum( kdata->value.ul );
114 } else {
115 mhz.setNum( 0 );
117 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "state" );
118 if( kdata != NULL ) {
119 state = QString( kdata->value.c );
120 } else {
121 state = "???";
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' );
128 *ptr = '\0';
129 state += " since " + QString( timetxt );
133 new Q3ListViewItem( lBox, inst, cputype, fputype, mhz, state );
136 // sorting_allowed = true;
137 lBox->setSorting( 0 );
139 return true;
142 bool GetInfo_IRQ( Q3ListView * ) {
143 return false;
146 bool GetInfo_DMA( Q3ListView * ) {
147 return false;
150 bool GetInfo_PCI( Q3ListView * ) {
151 return false;
154 bool GetInfo_IO_Ports( Q3ListView * ) {
155 return false;
158 bool GetInfo_Sound( Q3ListView * ) {
159 return false;
162 bool GetInfo_SCSI( Q3ListView * ) {
163 return false;
166 bool GetInfo_Partitions( Q3ListView *lBox ) {
168 FILE *mnttab;
169 struct mnttab mnt;
170 struct statvfs statbuf;
171 fsblkcnt_t tmp;
172 QString total;
173 QString avail;
174 time_t mnttime;
175 char *timetxt;
176 char *ptr;
178 if( (mnttab = fopen( MNTTAB, "r" )) == NULL ) {
179 return false;
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
200 rewind( mnttab );
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) )
213 continue;
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);
223 if( tmp > 9999 ) {
224 tmp /= 1024;
225 if( tmp > 9999 ) {
226 tmp /= 1024;
227 total.setNum( tmp );
228 total += " G";
229 } else {
230 total.setNum( tmp );
231 total += " M";
233 } else {
234 total.setNum( tmp );
235 total += " K";
237 // avail.setNum( statbuf.f_bavail );
238 // avail += " K";
239 tmp = statbuf.f_bavail
240 * (statbuf.f_frsize / 1024);
241 if( tmp > 9999 ) {
242 tmp /= 1024;
243 if( tmp > 9999 ) {
244 tmp /= 1024;
245 avail.setNum( tmp );
246 avail += " G";
247 } else {
248 avail.setNum( tmp );
249 avail += " M";
251 } else {
252 avail.setNum( tmp );
253 avail += " K";
255 } else {
256 total = "-";
257 avail = "-";
259 } else {
260 total = "???";
261 avail = "???";
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' );
270 *ptr = '\0';
273 new Q3ListViewItem(
274 lBox,
275 mnt.mnt_special,
276 mnt.mnt_mountp,
277 mnt.mnt_fstype,
278 total,
279 avail,
280 QString( timetxt ),
281 mnt.mnt_mntopts
284 fclose( mnttab );
286 lBox->setSorting( 0 );
287 // sorting_allowed = true;
289 return 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,
321 *previous,
322 *result;
323 char *str = strdup( path ),
324 *token;
327 * start at "/"
329 parent = top;
330 result = (*top).firstChild();
331 previous = (*top).firstChild();
333 token = strtok( str, "/" );
334 while( token != NULL ) {
336 * find insert pos:
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 )
345 break;
346 previous = result;
347 result = (*result).nextSibling();
349 if( result == NULL ) {
351 * we haven't found the node, create a new one
353 result = new Q3ListViewItem( parent,
354 previous,
355 token );
356 } else {
358 * we've found the node
360 parent = result;
361 previous = NULL;
362 if( (*result).firstChild() == NULL ) {
364 * create new node during next iteration
366 result->setExpandable( true );
367 result->setOpen( false );
368 } else {
370 * follow the child path
372 result = (*result).firstChild();
375 token = strtok( NULL, "/" );
377 free( str );
379 return( result );
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:
391 return( "BOOL" );
392 case DI_PROP_TYPE_INT:
393 return( "INT" );
394 case DI_PROP_TYPE_STRING:
395 return( "STRING" );
396 case DI_PROP_TYPE_BYTE:
397 return( "BYTE" );
398 default:
399 return( "unknown" );
404 * prop_type_guess() -- guess the property type
406 int prop_type_guess( uchar_t *data, int len ) {
408 int slen;
409 int guess;
410 int i, c;
412 if( len < 0 )
413 return( -1 );
414 else if( len == 0 )
415 return( DI_PROP_TYPE_BOOLEAN );
417 slen = 0;
418 guess = DI_PROP_TYPE_STRING;
420 for( i = 0; i < len; i++ ) {
421 c = (int) data[i];
422 switch( c ) {
423 case 0:
424 if( i == (len - 1 ))
425 break;
426 if( slen == 0 )
427 guess = DI_PROP_TYPE_BYTE;
428 else
429 guess = slen = 0;
430 break;
431 default:
432 if( ! isprint( c ))
433 guess = DI_PROP_TYPE_BYTE;
434 else
435 slen++;
437 if( guess != DI_PROP_TYPE_STRING )
438 break;
441 // if( (guess == DI_PROP_TYPE_BYTE) && (len % sizeof( int ) == 0 ))
442 // guess = DI_PROP_TYPE_INT;
444 return( guess );
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;
454 QString majmin;
455 char *type;
456 dev_t dev;
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 );
477 else
478 return( DI_WALK_CONTINUE );
482 * propvalue() -- return the property value
484 QString propvalue( di_prop_t prop ) {
486 int type;
487 int i, n;
488 char *strp;
489 int *intp;
490 uchar_t *bytep;
491 QString result;
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 );
504 result = "";
505 switch( type ) {
506 case DI_PROP_TYPE_STRING:
507 if( (n = di_prop_strings( prop, &strp )) < 0 ) {
508 result = "(error)";
509 } else {
510 for( i = 0; i < n; i++ ) {
511 result += "\"";
512 result += strp;
513 result += "\" ";
514 strp += strlen( strp ) + 1;
517 break;
518 case DI_PROP_TYPE_INT:
519 if( (n = di_prop_ints( prop, &intp )) < 0 ) {
520 result = "(error)";
521 } else {
522 for( i = 0; i < n; i++ ) {
523 QString tmp;
524 tmp.setNum( intp[i] );
525 result += tmp;
526 result += ' ';
529 break;
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 ) {
539 result = "(error)";
540 } else {
541 if( n == 0 ) {
542 result = i18n( "(no value)" );
543 break;
545 result = "0x";
546 for( i = 0; i < n; i++ ) {
547 QString tmp;
548 unsigned byte = (unsigned) bytep[i];
549 tmp.sprintf( "%2.2x", byte );
550 result += tmp;
553 break;
554 default:
555 result = "???";
558 return( result );
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,
568 *parent,
569 *previous;
570 char *path;
571 char *drivername;
572 char *names;
573 QString compatnames;
574 int i, n;
575 di_prop_t prop;
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 );
601 } else {
602 previous = parent;
603 parent = top;
607 * node name and physical device path
609 drivername = di_driver_name( node );
610 previous = new Q3ListViewItem( parent,
611 i18n( "Driver Name:" ),
612 (drivername == NULL)
613 ? i18n( "(driver not attached)" )
614 : drivername );
615 previous = new Q3ListViewItem( parent, previous,
616 i18n( "Binding Name:" ), di_binding_name( node ));
618 n = di_compatible_names( node, &names );
619 if( n < 1 ) {
620 compatnames = i18n( "(none)" );
621 } else {
622 for( i = 0; i < n; i++ ) {
623 compatnames += names;
624 compatnames += ' ';
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 );
642 do {
644 * property type & value
646 Q3ListViewItem *tmp,
647 *prev;
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:" ),
654 propvalue( prop ));
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 ) {
673 Q3ListViewItem *top;
674 di_node_t root_node;
677 * create a snapshot of the device tree
679 if( (root_node = di_init( "/", DINFOCPYALL )) == DI_NODE_NIL ) {
680 return( false );
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;
700 return true;
703 #else /* ! HAVE_LIBDEVINFO_H */
704 bool GetInfo_Devices( Q3ListView * ) {
705 return false;
707 #endif /* ! HAVE_LIBDEVINFO_H */