add more spacing
[personal-kdebase.git] / apps / kinfocenter / base / info_solaris.cpp
blob830ebfa6bb54d3af52bff592cd033c3988534d27
1 /*
2 * info_solaris.cpp
4 * Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
5 */
7 #include "config-infocenter.h"
9 #include <QTreeWidgetItemIterator>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/mnttab.h>
14 #include <kstat.h>
15 #include <sys/types.h>
16 #include <sys/statvfs.h>
17 #include <time.h>
19 #ifdef HAVE_LIBDEVINFO_H
20 #include <ctype.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/mkdev.h>
24 #include <sys/stat.h>
25 #include <devid.h>
26 #include <libdevinfo.h>
27 #endif /* HAVE_LIBDEVINFO_H */
29 bool GetInfo_CPU(QTreeWidget* tree) {
31 kstat_ctl_t *kctl;
32 kstat_t *ksp;
33 kstat_named_t *kdata;
34 char cputype[16], fputype[16];
35 char *timetxt;
36 char *ptr;
37 uint32_t i, ncpus;
38 unsigned long state_begin;
39 QString state;
40 QString mhz;
41 QString inst;
44 * get a kstat handle first and update the user's kstat chain
46 if ( (kctl = kstat_open()) == NULL) {
47 return false;
49 while (kstat_chain_update(kctl) != 0)
53 * get the # of CPUs
55 if ( (ksp = kstat_lookup(kctl, "unix", 0, "system_misc")) == NULL) {
56 return false;
58 if (kstat_read(kctl, ksp, NULL) == -1) {
59 return false;
61 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "ncpus");
62 if (kdata != NULL) {
63 ncpus = kdata->value.ui32;
64 } else {
65 ncpus = 0;
68 QStringList headers;
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) {
78 return false;
81 if (kstat_read(kctl, ksp, NULL) == -1) {
82 return false;
85 inst.setNum(i);
86 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_type");
87 if (kdata != NULL) {
88 strcpy(cputype, kdata->value.c);
89 } else {
90 sprintf(cputype, "???");
92 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "fpu_type");
93 if (kdata != NULL) {
94 strcpy(fputype, kdata->value.c);
95 } else {
96 sprintf(fputype, "???");
98 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz");
99 if (kdata != NULL) {
100 mhz.setNum(kdata->value.ul);
101 } else {
102 mhz.setNum( 0);
104 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "state");
105 if (kdata != NULL) {
106 state = QString(kdata->value.c);
107 } else {
108 state = "???";
110 kdata = (kstat_named_t *) kstat_data_lookup(ksp, "state_begin");
111 if (kdata != NULL) {
112 state_begin = kdata->value.i32;
113 if ( (timetxt = ctime( (time_t *) &state_begin )) != NULL) {
114 ptr = strrchr(timetxt, '\n');
115 *ptr = '\0';
116 state += " since " + QString(timetxt);
120 QStringList list;
121 list << inst << cputype << fputype << mhz << state;
122 new QTreeWidgetItem(tree, list);
125 tree->sortItems(0, Qt::AscendingOrder);
127 return true;
130 bool GetInfo_IRQ(QTreeWidget*) {
131 return false;
134 bool GetInfo_DMA(QTreeWidget*) {
135 return false;
138 bool GetInfo_PCI(QTreeWidget*) {
139 return false;
142 bool GetInfo_IO_Ports(QTreeWidget*) {
143 return false;
146 bool GetInfo_Sound(QTreeWidget*) {
147 return false;
150 bool GetInfo_SCSI(QTreeWidget*) {
151 return false;
154 bool GetInfo_Partitions(QTreeWidget* tree) {
156 FILE *mnttab;
157 struct mnttab mnt;
158 struct statvfs statbuf;
159 fsblkcnt_t tmp;
160 QString total;
161 QString avail;
162 time_t mnttime;
163 char *timetxt;
164 char *ptr;
166 if ( (mnttab = fopen(MNTTAB, "r")) == NULL) {
167 return false;
171 * set up column headers
173 QStringList 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
185 rewind(mnttab);
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))
197 continue;
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);
206 if (tmp > 9999) {
207 tmp /= 1024;
208 if (tmp > 9999) {
209 tmp /= 1024;
210 total.setNum(tmp);
211 total += " G";
212 } else {
213 total.setNum(tmp);
214 total += " M";
216 } else {
217 total.setNum(tmp);
218 total += " K";
220 // avail.setNum( statbuf.f_bavail );
221 // avail += " K";
222 tmp = statbuf.f_bavail * (statbuf.f_frsize / 1024);
223 if (tmp > 9999) {
224 tmp /= 1024;
225 if (tmp > 9999) {
226 tmp /= 1024;
227 avail.setNum(tmp);
228 avail += " G";
229 } else {
230 avail.setNum(tmp);
231 avail += " M";
233 } else {
234 avail.setNum(tmp);
235 avail += " K";
237 } else {
238 total = "-";
239 avail = "-";
241 } else {
242 total = "???";
243 avail = "???";
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');
252 *ptr = '\0';
255 QStringList list;
256 list << mnt.mnt_special << mnt.mnt_mountp << mnt.mnt_fstype << total << avail << QString(timetxt) << mnt.mnt_mntopts;
257 new QTreeWidgetItem(tree, list);
259 fclose(mnttab);
261 tree->sortItems(0, Qt::AscendingOrder);
263 return true;
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 );
298 char* token;
301 * start at "/"
303 parent = top;
304 result = top->child(0);
305 previous = top->child(0);
307 token = strtok( str, "/" );
308 while( token != NULL ) {
310 * find insert pos:
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 )
320 break;
322 previous = *it;
324 ++it;
325 result = *it;
327 if( result == NULL ) {
328 QStringList list;
329 list << token;
332 * we haven't found the node, create a new one
334 result = new QTreeWidgetItem(parent, previous, list);
336 else {
338 * we've found the node
340 parent = result;
341 previous = NULL;
342 if( result->child(0) == NULL ) {
344 * create new node during next iteration
346 result->setExpanded(false);
347 } else {
349 * follow the child path
351 result = result->child(0);
354 token = strtok( NULL, "/" );
357 free( str );
359 return result;
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:
371 return( "BOOL" );
372 case DI_PROP_TYPE_INT:
373 return( "INT" );
374 case DI_PROP_TYPE_STRING:
375 return( "STRING" );
376 case DI_PROP_TYPE_BYTE:
377 return( "BYTE" );
378 default:
379 return( "unknown" );
384 * prop_type_guess() -- guess the property type
386 int prop_type_guess( uchar_t *data, int len ) {
388 int slen;
389 int guess;
390 int i, c;
392 if( len < 0 )
393 return( -1 );
394 else if( len == 0 )
395 return( DI_PROP_TYPE_BOOLEAN );
397 slen = 0;
398 guess = DI_PROP_TYPE_STRING;
400 for( i = 0; i < len; i++ ) {
401 c = (int) data[i];
402 switch( c ) {
403 case 0:
404 if( i == (len - 1 ))
405 break;
406 if( slen == 0 )
407 guess = DI_PROP_TYPE_BYTE;
408 else
409 guess = slen = 0;
410 break;
411 default:
412 if( ! isprint( c ))
413 guess = DI_PROP_TYPE_BYTE;
414 else
415 slen++;
417 if( guess != DI_PROP_TYPE_STRING )
418 break;
421 // if( (guess == DI_PROP_TYPE_BYTE) && (len % sizeof( int ) == 0 ))
422 // guess = DI_PROP_TYPE_INT;
424 return( guess );
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 ) {
433 QString majmin;
434 char *type;
435 dev_t dev;
437 QStringList list;
438 list << di_minor_name( minor );
439 QTreeWidgetItem* item = new QTreeWidgetItem( (QTreeWidgetItem *) arg, list);
440 item->setExpanded(false);
442 QString specResult;
443 if (di_minor_spectype( minor ) == S_IFCHR)
444 specResult = i18n( "character special" );
445 else
446 specResult = i18n( "block special" );
448 QStringList spec;
449 spec << i18n( "Spectype:" ) << specResult;
451 new QTreeWidgetItem(item, spec);
453 type = di_minor_nodetype( minor );
455 QString nodeResult;
456 if (type == NULL)
457 nodeResult = "NULL";
458 else
459 nodeResult = type;
461 QStringList node;
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 ));
468 QStringList mn;
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;
475 else
476 return DI_WALK_CONTINUE;
480 * propvalue() -- return the property value
482 QString propvalue( di_prop_t prop ) {
484 int type;
485 int i, n;
486 char *strp;
487 int *intp;
488 uchar_t *bytep;
489 QString result;
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 );
502 result = "";
503 switch( type ) {
504 case DI_PROP_TYPE_STRING:
505 if( (n = di_prop_strings( prop, &strp )) < 0 ) {
506 result = "(error)";
507 } else {
508 for( i = 0; i < n; i++ ) {
509 result += "\"";
510 result += strp;
511 result += "\" ";
512 strp += strlen( strp ) + 1;
515 break;
516 case DI_PROP_TYPE_INT:
517 if( (n = di_prop_ints( prop, &intp )) < 0 ) {
518 result = "(error)";
519 } else {
520 for( i = 0; i < n; i++ ) {
521 QString tmp;
522 tmp.setNum( intp[i] );
523 result += tmp;
524 result += ' ';
527 break;
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 ) {
537 result = "(error)";
538 } else {
539 if( n == 0 ) {
540 result = i18n( "(no value)" );
541 break;
543 result = "0x";
544 for( i = 0; i < n; i++ ) {
545 QString tmp;
546 unsigned byte = (unsigned) bytep[i];
547 tmp.sprintf( "%2.2x", byte );
548 result += tmp;
551 break;
552 default:
553 result = "???";
556 return( result );
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;
567 char *path;
568 char *drivername;
569 char *names;
570 QString compatnames;
571 int i, n;
572 di_prop_t prop;
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);
595 } else {
596 parent = top;
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)" );
608 else
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 );
618 if( n < 1 ) {
619 compatnames = i18n( "(none)" );
620 } else {
621 for( i = 0; i < n; i++ ) {
622 compatnames += names;
623 compatnames += ' ';
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 );
647 do {
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 ) {
683 di_node_t root_node;
686 * create a snapshot of the device tree
688 if( (root_node = di_init( "/", DINFOCPYALL )) == DI_NODE_NIL ) {
689 return( false );
691 // XXX: might try to di_prom_init() here as well (if we're setgid sys)
694 * prepare the tree widget
696 QStringList headers;
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);
711 return true;
714 #else /* ! HAVE_LIBDEVINFO_H */
715 bool GetInfo_Devices(QTreeWidget*) {
716 return false;
718 #endif /* ! HAVE_LIBDEVINFO_H */