Beispiel #1
0
/*
 ***************************************************************************
 * Display disk stats header.
 *
 * OUT:
 * @fctr	Conversion factor.
 ***************************************************************************
 */
void write_disk_stat_header(int *fctr)
{
	if (DISPLAY_EXTENDED(flags)) {
		/* Extended stats */
		printf("Device:         rrqm/s   wrqm/s     r/s     w/s");
		if (DISPLAY_MEGABYTES(flags)) {
			printf("    rMB/s    wMB/s");
			*fctr = 2048;
		}
		else if (DISPLAY_KILOBYTES(flags)) {
			printf("    rkB/s    wkB/s");
			*fctr = 2;
		}
		else {
			printf("   rsec/s   wsec/s");
		}
		printf(" avgrq-sz avgqu-sz   await r_await w_await  svctm  %%util\n");
	}
	else {
		/* Basic stats */
		printf("Device:            tps");
		if (DISPLAY_KILOBYTES(flags)) {
			printf("    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn\n");
			*fctr = 2;
		}
		else if (DISPLAY_MEGABYTES(flags)) {
			printf("    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn\n");
			*fctr = 2048;
		}
		else {
			printf("   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn\n");
		}
	}
}
Beispiel #2
0
/*
 ***************************************************************************
 * Read sysfs stat for current block device or partition.
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 * @filename	File name where stats will be read.
 * @dev_name	Device or partition name.
 *
 * RETURNS:
 * 0 if file couldn't be opened, 1 otherwise.
 ***************************************************************************
 */
int read_sysfs_file_stat(int curr, char *filename, char *dev_name)
{
	FILE *fp;
	struct io_stats sdev;
	int i;
	unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
	unsigned long rd_ios, rd_merges_or_rd_sec, wr_ios, wr_merges;
	unsigned long rd_sec_or_wr_ios, wr_sec, rd_ticks_or_wr_sec;

	/* Try to read given stat file */
	if ((fp = fopen(filename, "r")) == NULL)
		return 0;

	i = fscanf(fp, "%lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
		   &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
		   &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);

	if (i == 11) {
		/* Device or partition */
		sdev.rd_ios     = rd_ios;
		sdev.rd_merges  = rd_merges_or_rd_sec;
		sdev.rd_sectors = rd_sec_or_wr_ios;
		sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
		sdev.wr_ios     = wr_ios;
		sdev.wr_merges  = wr_merges;
		sdev.wr_sectors = wr_sec;
		sdev.wr_ticks   = wr_ticks;
		sdev.ios_pgr    = ios_pgr;
		sdev.tot_ticks  = tot_ticks;
		sdev.rq_ticks   = rq_ticks;
	}
	else if (i == 4) {
		/* Partition without extended statistics */
		sdev.rd_ios     = rd_ios;
		sdev.rd_sectors = rd_merges_or_rd_sec;
		sdev.wr_ios     = rd_sec_or_wr_ios;
		sdev.wr_sectors = rd_ticks_or_wr_sec;
	}

	if ((i == 11) || !DISPLAY_EXTENDED(flags)) {
		/*
		 * In fact, we _don't_ save stats if it's a partition without
		 * extended stats and yet we want to display ext stats.
		 */
		save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
	}

	fclose(fp);

	return 1;
}
Beispiel #3
0
/*
 ***************************************************************************
 * Read stats from /proc/diskstats.
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 ***************************************************************************
 */
void read_diskstats_stat(int curr)
{
	FILE *fp;
	char line[256], dev_name[MAX_NAME_LEN];
	char *dm_name;
	struct io_stats sdev;
	int i;
	unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
	unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
	unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
	char *ioc_dname;
	unsigned int major, minor;

	/* Every I/O device entry is potentially unregistered */
	set_entries_unregistered(iodev_nr, st_hdr_iodev);

	if ((fp = fopen(DISKSTATS, "r")) == NULL)
		return;

	while (fgets(line, sizeof(line), fp) != NULL) {

		/* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */
		i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
			   &major, &minor, dev_name,
			   &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
			   &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);

		if (i == 14) {
			/* Device or partition */
			if (!dlist_idx && !DISPLAY_PARTITIONS(flags) &&
			    !is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
				continue;
			sdev.rd_ios     = rd_ios;
			sdev.rd_merges  = rd_merges_or_rd_sec;
			sdev.rd_sectors = rd_sec_or_wr_ios;
			sdev.rd_ticks   = (unsigned int) rd_ticks_or_wr_sec;
			sdev.wr_ios     = wr_ios;
			sdev.wr_merges  = wr_merges;
			sdev.wr_sectors = wr_sec;
			sdev.wr_ticks   = wr_ticks;
			sdev.ios_pgr    = ios_pgr;
			sdev.tot_ticks  = tot_ticks;
			sdev.rq_ticks   = rq_ticks;
		}
		else if (i == 7) {
			/* Partition without extended statistics */
			if (DISPLAY_EXTENDED(flags) ||
			    (!dlist_idx && !DISPLAY_PARTITIONS(flags)))
				continue;

			sdev.rd_ios     = rd_ios;
			sdev.rd_sectors = rd_merges_or_rd_sec;
			sdev.wr_ios     = rd_sec_or_wr_ios;
			sdev.wr_sectors = rd_ticks_or_wr_sec;
		}
		else
			/* Unknown entry: Ignore it */
			continue;

		if ((ioc_dname = ioc_name(major, minor)) != NULL) {
			if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) {
				/*
				 * No match: Use name generated from sysstat.ioconf data
				 * (if different from "nodev") works around known issues
				 * with EMC PowerPath.
				 */
				strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1);
				dev_name[MAX_NAME_LEN - 1] = '\0';
			}
		}

		if ((DISPLAY_DEVMAP_NAME(flags)) && (major == dm_major)) {
			/*
			 * If the device is a device mapper device, try to get its
			 * assigned name of its logical device.
			 */
			dm_name = transform_devmapname(major, minor);
			if (dm_name) {
				strncpy(dev_name, dm_name, MAX_NAME_LEN - 1);
				dev_name[MAX_NAME_LEN - 1] = '\0';
			}
		}

		save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
	}
	fclose(fp);

	/* Free structures corresponding to unregistered devices */
	free_unregistered_entries(iodev_nr, st_hdr_iodev);
}
Beispiel #4
0
/*
 ***************************************************************************
 * Main entry to the iostat program.
 ***************************************************************************
 */
int main(int argc, char **argv)
{
	int it = 0;
	int opt = 1;
	int i, report_set = FALSE;
	long count = 1;
	struct utsname header;
	struct io_dlist *st_dev_list_i;
	struct tm rectime;
	char *t, *persist_devname, *devname;

#ifdef USE_NLS
	/* Init National Language Support */
	init_nls();
#endif

	/* Get HZ */
	get_HZ();

	/* Allocate structures for device list */
	if (argc > 1) {
		salloc_dev_list(argc - 1 + count_csvalues(argc, argv));
	}

	/* Process args... */
	while (opt < argc) {

		/* -p option used individually. See below for grouped use */
		if (!strcmp(argv[opt], "-p")) {
			flags |= I_D_PARTITIONS;
			if (argv[++opt] &&
			    (strspn(argv[opt], DIGITS) != strlen(argv[opt])) &&
			    (strncmp(argv[opt], "-", 1))) {
				flags |= I_D_UNFILTERED;

				for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
					if (!strcmp(t, K_ALL)) {
						flags |= I_D_PART_ALL;
					}
					else {
						devname = device_name(t);
						if (DISPLAY_PERSIST_NAME_I(flags)) {
							/* Get device persistent name */
							persist_devname = get_pretty_name_from_persistent(devname);
							if (persist_devname != NULL) {
								devname = persist_devname;
							}
						}
						/* Store device name */
						i = update_dev_list(&dlist_idx, devname);
						st_dev_list_i = st_dev_list + i;
						st_dev_list_i->disp_part = TRUE;
					}
				}
				opt++;
			}
			else {
				flags |= I_D_PART_ALL;
			}
		}

		else if (!strcmp(argv[opt], "-g")) {
			/*
			 * Option -g: Stats for a group of devices.
			 * group_name contains the last group name entered on
			 * the command line. If we define an additional one, save
			 * the previous one in the list. We do that this way because we
			 * want the group name to appear in the list _after_ all
			 * the devices included in that group. The last group name
			 * will be saved in the list later, in presave_device_list() function.
			 */
			if (group_nr > 0) {
				update_dev_list(&dlist_idx, group_name);
			}
			if (argv[++opt]) {
				/*
				 * MAX_NAME_LEN - 2: one char for the heading space,
				 * and one for the trailing '\0'.
				 */
				snprintf(group_name, MAX_NAME_LEN, " %-.*s", MAX_NAME_LEN - 2, argv[opt++]);
			}
			else {
				usage(argv[0]);
			}
			group_nr++;
		}

		else if (!strcmp(argv[opt], "-j")) {
			if (argv[++opt]) {
				if (strnlen(argv[opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1) {
					usage(argv[0]);
				}
				strncpy(persistent_name_type, argv[opt], MAX_FILE_LEN - 1);
				persistent_name_type[MAX_FILE_LEN - 1] = '\0';
				strtolower(persistent_name_type);
				/* Check that this is a valid type of persistent device name */
				if (!get_persistent_type_dir(persistent_name_type)) {
					fprintf(stderr, _("Invalid type of persistent device name\n"));
					exit(1);
				}
				/*
				 * Persistent names are usually long: Display
				 * them as human readable by default.
				 */
				flags |= I_D_PERSIST_NAME + I_D_HUMAN_READ;
				opt++;
			}
			else {
				usage(argv[0]);
			}
		}

#ifdef DEBUG
		else if (!strcmp(argv[opt], "--debuginfo")) {
			flags |= I_D_DEBUG;
			opt++;
		}
#endif

		else if (!strncmp(argv[opt], "-", 1)) {
			for (i = 1; *(argv[opt] + i); i++) {

				switch (*(argv[opt] + i)) {

				case 'c':
					/* Display cpu usage */
					flags |= I_D_CPU;
					report_set = TRUE;
					break;

				case 'd':
					/* Display disk utilization */
					flags |= I_D_DISK;
					report_set = TRUE;
					break;

				case 'h':
					/*
					 * Display device utilization report
					 * in a human readable format.
					 */
					flags |= I_D_HUMAN_READ;
					break;

				case 'k':
					if (DISPLAY_MEGABYTES(flags)) {
						usage(argv[0]);
					}
					/* Display stats in kB/s */
					flags |= I_D_KILOBYTES;
					break;

				case 'm':
					if (DISPLAY_KILOBYTES(flags)) {
						usage(argv[0]);
					}
					/* Display stats in MB/s */
					flags |= I_D_MEGABYTES;
					break;

				case 'N':
					/* Display device mapper logical name */
					flags |= I_D_DEVMAP_NAME;
					break;

				case 'p':
					/* If option -p is grouped then it cannot take an arg */
					flags |= I_D_PARTITIONS + I_D_PART_ALL;
					break;

				case 'T':
					/* Display stats only for the groups */
					flags |= I_D_GROUP_TOTAL_ONLY;
					break;

				case 't':
					/* Display timestamp */
					flags |= I_D_TIMESTAMP;
					break;

				case 'x':
					/* Display extended stats */
					flags |= I_D_EXTENDED;
					break;

				case 'y':
					/* Don't display stats since system restart */
					flags |= I_D_OMIT_SINCE_BOOT;
					break;

				case 'z':
					/* Omit output for devices with no activity */
					flags |= I_D_ZERO_OMIT;
					break;

				case 'V':
					/* Print version number and exit */
					print_version();
					break;

				default:
					usage(argv[0]);
				}
			}
			opt++;
		}

		else if (!isdigit(argv[opt][0])) {
			/*
			 * By default iostat doesn't display unused devices.
			 * If some devices are explictly entered on the command line
			 * then don't apply this rule any more.
			 */
			flags |= I_D_UNFILTERED;

			if (strcmp(argv[opt], K_ALL)) {
				/* Store device name entered on the command line */
				devname = device_name(argv[opt++]);
				if (DISPLAY_PERSIST_NAME_I(flags)) {
					persist_devname = get_pretty_name_from_persistent(devname);
					if (persist_devname != NULL) {
						devname = persist_devname;
					}
				}
				update_dev_list(&dlist_idx, devname);
			}
			else {
				opt++;
			}
		}

		else if (!it) {
			interval = atol(argv[opt++]);
			if (interval < 0) {
				usage(argv[0]);
			}
			count = -1;
			it = 1;
		}

		else if (it > 0) {
			count = atol(argv[opt++]);
			if ((count < 1) || !interval) {
				usage(argv[0]);
			}
			it = -1;
		}
		else {
			usage(argv[0]);
		}
	}

	if (!interval) {
		count = 1;
	}

	/* Default: Display CPU and DISK reports */
	if (!report_set) {
		flags |= I_D_CPU + I_D_DISK;
	}
	/*
	 * Also display DISK reports if options -p, -x or a device has been entered
	 * on the command line.
	 */
	if (DISPLAY_PARTITIONS(flags) || DISPLAY_EXTENDED(flags) ||
	    DISPLAY_UNFILTERED(flags)) {
		flags |= I_D_DISK;
	}

	/* Option -T can only be used with option -g */
	if (DISPLAY_GROUP_TOTAL_ONLY(flags) && !group_nr) {
		usage(argv[0]);
	}

	/* Select disk output unit (kB/s or blocks/s) */
	set_disk_output_unit();

	/* Ignore device list if '-p ALL' entered on the command line */
	if (DISPLAY_PART_ALL(flags)) {
		dlist_idx = 0;
	}

	if (DISPLAY_DEVMAP_NAME(flags)) {
		dm_major = get_devmap_major();
	}

	/* Init structures according to machine architecture */
	io_sys_init();
	if (group_nr > 0) {
		/*
		 * If groups of devices have been defined
		 * then save devices and groups in the list.
		 */
		presave_device_list();
	}

	get_localtime(&rectime, 0);

	/* Get system name, release number and hostname */
	uname(&header);
	if (print_gal_header(&rectime, header.sysname, header.release,
			     header.nodename, header.machine, cpu_nr)) {
		flags |= I_D_ISO;
	}
	printf("\n");

	/* Set a handler for SIGALRM */
	memset(&alrm_act, 0, sizeof(alrm_act));
	alrm_act.sa_handler = alarm_handler;
	sigaction(SIGALRM, &alrm_act, NULL);
	alarm(interval);

	/* Main loop */
	rw_io_stat_loop(count, &rectime);

	/* Free structures */
	io_sys_free();
	sfree_dev_list();

	return 0;
}
Beispiel #5
0
/*
 ***************************************************************************
 * Print everything now (stats and uptime).
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 * @rectime	Current date and time.
 ***************************************************************************
 */
void write_stats(int curr, struct tm *rectime)
{
	int dev, i, fctr = 1;
	unsigned long long itv;
	struct io_hdr_stats *shi;
	struct io_dlist *st_dev_list_i;

	/* Test stdout */
	TEST_STDOUT(STDOUT_FILENO);

	/* Print time stamp */
	if (DISPLAY_TIMESTAMP(flags)) {
		if (DISPLAY_ISO(flags)) {
			strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime);
		}
		else {
			strftime(timestamp, sizeof(timestamp), "%x %X", rectime);
		}
		printf("%s\n", timestamp);
#ifdef DEBUG
		if (DISPLAY_DEBUG(flags)) {
			fprintf(stderr, "%s\n", timestamp);
		}
#endif
	}

	/* Interval is multiplied by the number of processors */
	itv = get_interval(uptime[!curr], uptime[curr]);

	if (DISPLAY_CPU(flags)) {
#ifdef DEBUG
		if (DISPLAY_DEBUG(flags)) {
			/* Debug output */
			fprintf(stderr, "itv=%llu st_cpu[curr]{ cpu_user=%llu cpu_nice=%llu "
					"cpu_sys=%llu cpu_idle=%llu cpu_iowait=%llu cpu_steal=%llu "
					"cpu_hardirq=%llu cpu_softirq=%llu cpu_guest=%llu "
					"cpu_guest_nice=%llu }\n",
				itv,
				st_cpu[curr]->cpu_user,
				st_cpu[curr]->cpu_nice,
				st_cpu[curr]->cpu_sys,
				st_cpu[curr]->cpu_idle,
				st_cpu[curr]->cpu_iowait,
				st_cpu[curr]->cpu_steal,
				st_cpu[curr]->cpu_hardirq,
				st_cpu[curr]->cpu_softirq,
				st_cpu[curr]->cpu_guest,
				st_cpu[curr]->cpu_guest_nice);
		}
#endif

		/* Display CPU utilization */
		write_cpu_stat(curr, itv);
	}

	if (cpu_nr > 1) {
		/* On SMP machines, reduce itv to one processor (see note above) */
		itv = get_interval(uptime0[!curr], uptime0[curr]);
	}

	if (DISPLAY_DISK(flags)) {
		struct io_stats *ioi, *ioj;

		shi = st_hdr_iodev;

		/* Display disk stats header */
		write_disk_stat_header(&fctr);

		for (i = 0; i < iodev_nr; i++, shi++) {
			if (shi->used) {

				if (dlist_idx && !HAS_SYSFS(flags)) {
					/*
					 * With /proc/diskstats, stats for every device
					 * are read even if we have entered a list on devices
					 * on the command line. Thus we need to check
					 * if stats for current device are to be displayed.
					 */
					for (dev = 0; dev < dlist_idx; dev++) {
						st_dev_list_i = st_dev_list + dev;
						if (!strcmp(shi->name, st_dev_list_i->dev_name))
							break;
					}
					if (dev == dlist_idx)
						/* Device not found in list: Don't display it */
						continue;
				}

				ioi = st_iodev[curr] + i;
				ioj = st_iodev[!curr] + i;

				if (!DISPLAY_UNFILTERED(flags)) {
					if (!ioi->rd_ios && !ioi->wr_ios)
						continue;
				}

				if (DISPLAY_ZERO_OMIT(flags)) {
					if ((ioi->rd_ios == ioj->rd_ios) &&
						(ioi->wr_ios == ioj->wr_ios))
						/* No activity: Ignore it */
						continue;
				}

				if (DISPLAY_GROUP_TOTAL_ONLY(flags)) {
					if (shi->status != DISK_GROUP)
						continue;
				}
#ifdef DEBUG
				if (DISPLAY_DEBUG(flags)) {
					/* Debug output */
					fprintf(stderr, "name=%s itv=%llu fctr=%d ioi{ rd_sectors=%lu "
							"wr_sectors=%lu rd_ios=%lu rd_merges=%lu rd_ticks=%u "
							"wr_ios=%lu wr_merges=%lu wr_ticks=%u ios_pgr=%u tot_ticks=%u "
							"rq_ticks=%u }\n",
						shi->name,
						itv,
						fctr,
						ioi->rd_sectors,
						ioi->wr_sectors,
						ioi->rd_ios,
						ioi->rd_merges,
						ioi->rd_ticks,
						ioi->wr_ios,
						ioi->wr_merges,
						ioi->wr_ticks,
						ioi->ios_pgr,
						ioi->tot_ticks,
						ioi->rq_ticks
						);
				}
#endif

				if (DISPLAY_EXTENDED(flags)) {
					write_ext_stat(curr, itv, fctr, shi, ioi, ioj);
				}
				else {
					write_basic_stat(curr, itv, fctr, shi, ioi, ioj);
				}
			}
		}
		printf("\n");
	}
}
Beispiel #6
0
/*
 ***************************************************************************
 * Read stats from /proc/diskstats
 ***************************************************************************
 */
void read_diskstats_stat(int curr, int flags)
{
   FILE *fp;
   char line[256], dev_name[MAX_NAME_LEN];
   struct io_stats sdev;
   int i;
   unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
   unsigned long ios_pgr, tot_ticks, rq_ticks, wr_merges, wr_ticks;
   unsigned long long rd_sec_or_wr_ios, wr_sec;
   char *ioc_dname;
   unsigned int major, minor;

   /* Every I/O device entry is potentially unregistered */
   set_entries_inactive(iodev_nr);

   if ((fp = fopen(DISKSTATS, "r")) == NULL)
      return;

   while (fgets(line, 256, fp) != NULL) {

      /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */
      i = sscanf(line, "%u %u %s %lu %lu %llu %lu %lu %lu %llu %lu %lu %lu %lu",
		 &major, &minor, dev_name,
		 &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
		 &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);

      if (i == 14) {
	 /* Device */
	 sdev.rd_ios     = rd_ios;
	 sdev.rd_merges  = rd_merges_or_rd_sec;
	 sdev.rd_sectors = rd_sec_or_wr_ios;
	 sdev.rd_ticks   = rd_ticks_or_wr_sec;
	 sdev.wr_ios     = wr_ios;
	 sdev.wr_merges  = wr_merges;
	 sdev.wr_sectors = wr_sec;
	 sdev.wr_ticks   = wr_ticks;
	 sdev.ios_pgr    = ios_pgr;
	 sdev.tot_ticks  = tot_ticks;
	 sdev.rq_ticks   = rq_ticks;
      }
      else if (i == 7) {
	 /* Partition */
	 if (DISPLAY_EXTENDED(flags) || (!dlist_idx && !DISPLAY_PARTITIONS(flags)))
	    continue;

	 sdev.rd_ios     = rd_ios;
	 sdev.rd_sectors = rd_merges_or_rd_sec;
	 sdev.wr_ios     = rd_sec_or_wr_ios;
	 sdev.wr_sectors = rd_ticks_or_wr_sec;
      }
      else
	 /* Unknown entry: ignore it */
	 continue;

      if ((ioc_dname = ioc_name(major, minor)) != NULL) {
	 if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV))
	    /*
	     * No match: Use name generated from sysstat.ioconf data (if different
	     * from "nodev") works around known issues with EMC PowerPath.
	     */
	    strcpy(dev_name, ioc_dname);
      }

      save_dev_stats(dev_name, curr, &sdev);
   }

   fclose(fp);

   /* Free structures corresponding to unregistered devices */
   free_inactive_entries(iodev_nr);
}
Beispiel #7
0
/*
 ***************************************************************************
 * Read stats from /proc/stat file...
 * Useful at least for CPU utilization.
 * May be useful to get disk stats if /sys not available.
 ***************************************************************************
 */
void read_proc_stat(int curr, int flags)
{
   FILE *fp;
   char line[8192];
   int pos, i;
   unsigned long v_tmp[4];
   unsigned int v_major, v_index;
   struct io_stats *st_iodev_tmp[4];
   unsigned long long cc_idle, cc_iowait, cc_steal;
   unsigned long long cc_user, cc_nice, cc_system, cc_hardirq, cc_softirq;


   /*
    * Prepare pointers on the 4 disk structures in case we have a
    * /proc/stat file with "disk_rblk", etc. entries.
    */
   for (i = 0; i < 4; i++)
      st_iodev_tmp[i] = st_iodev[curr] + i;

   if ((fp = fopen(STAT, "r")) == NULL) {
      perror("fopen");
      exit(2);
   }

   while (fgets(line, 8192, fp) != NULL) {

      if (!strncmp(line, "cpu ", 4)) {
	 /*
	  * Read the number of jiffies spent in the different modes,
	  * and compute system uptime in jiffies (1/100ths of a second
	  * if HZ=100).
	  * Some fields are only present in 2.6 kernels.
	  */
	 comm_stats[curr].cpu_iowait = 0;	/* For pre 2.6 kernels */
	 comm_stats[curr].cpu_steal = 0;
	 cc_hardirq = cc_softirq = 0;
	 /* CPU counters became unsigned long long with kernel 2.6.5 */
	 sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu",
	        &(comm_stats[curr].cpu_user), &(comm_stats[curr].cpu_nice),
		&(comm_stats[curr].cpu_system), &(comm_stats[curr].cpu_idle),
		&(comm_stats[curr].cpu_iowait), &cc_hardirq, &cc_softirq,
		&(comm_stats[curr].cpu_steal));

	 /*
	  * Time spent in system mode also includes time spent servicing
	  * hard interrupts and softirqs.
	  */
	 comm_stats[curr].cpu_system += cc_hardirq + cc_softirq;
	
	 /*
	  * Compute system uptime in jiffies.
	  * Uptime is multiplied by the number of processors.
	  */
	 comm_stats[curr].uptime = comm_stats[curr].cpu_user +
	                           comm_stats[curr].cpu_nice +
	                           comm_stats[curr].cpu_system +
	                           comm_stats[curr].cpu_idle +
	                           comm_stats[curr].cpu_iowait +
	    			   comm_stats[curr].cpu_steal;
      }

      else if ((!strncmp(line, "cpu0", 4)) && (cpu_nr > 1)) {
	 /*
	  * Read CPU line for proc#0 (if available).
	  * This is necessary to compute time interval since
	  * processors may be disabled (offline) sometimes.
	  * (Assume that proc#0 can never be offline).
	  */
	 cc_iowait = cc_hardirq = cc_softirq = cc_steal = 0;
	 sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu",
		&cc_user, &cc_nice, &cc_system, &cc_idle, &cc_iowait,
		&cc_hardirq, &cc_softirq, &cc_steal);
	 comm_stats[curr].uptime0 = cc_user + cc_nice + cc_system +
	    			    cc_idle + cc_iowait +
	    			    cc_hardirq + cc_softirq + cc_steal;
      }

      else if (DISPLAY_EXTENDED(flags) || HAS_DISKSTATS(flags) ||
	       HAS_PPARTITIONS(flags) || HAS_SYSFS(flags))
	 /*
	  * When displaying extended statistics, or if /proc/diskstats or
	  * /proc/partitions exists, or /sys is mounted,
	  * we just need to get CPU info from /proc/stat.
	  */
	 continue;

      else if (!strncmp(line, "disk_rblk ", 10)) {
	 /*
	  * Read the number of blocks read from disk.
	  * A block is of indeterminate size.
	  * The size may vary depending on the device type.
	  */
	 sscanf(line + 10, "%lu %lu %lu %lu",
		&v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]);

	 st_iodev_tmp[0]->dk_drive_rblk = v_tmp[0];
	 st_iodev_tmp[1]->dk_drive_rblk = v_tmp[1];
	 st_iodev_tmp[2]->dk_drive_rblk = v_tmp[2];
	 st_iodev_tmp[3]->dk_drive_rblk = v_tmp[3];
      }

      else if (!strncmp(line, "disk_wblk ", 10)) {
	 /* Read the number of blocks written to disk */
	 sscanf(line + 10, "%lu %lu %lu %lu",
		&v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]);
	
	 st_iodev_tmp[0]->dk_drive_wblk = v_tmp[0];
	 st_iodev_tmp[1]->dk_drive_wblk = v_tmp[1];
	 st_iodev_tmp[2]->dk_drive_wblk = v_tmp[2];
	 st_iodev_tmp[3]->dk_drive_wblk = v_tmp[3];
      }

      else if (!strncmp(line, "disk ", 5)) {
	 /* Read the number of I/O done since the last reboot */
	 sscanf(line + 5, "%lu %lu %lu %lu",
		&v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]);
	
	 st_iodev_tmp[0]->dk_drive = v_tmp[0];
	 st_iodev_tmp[1]->dk_drive = v_tmp[1];
	 st_iodev_tmp[2]->dk_drive = v_tmp[2];
	 st_iodev_tmp[3]->dk_drive = v_tmp[3];
      }

      else if (!strncmp(line, "disk_io: ", 9)) {
	 struct io_stats sdev;
	 char dev_name[MAX_NAME_LEN];
	
	 pos = 9;

	 /* Every disk_io entry is potentially unregistered */
	 set_entries_inactive(iodev_nr);
	
	 /* Read disks I/O statistics (for 2.4 kernels) */
	 while (pos < strlen(line) - 1) {
	    /* Beware: a CR is already included in the line */
	    sscanf(line + pos, "(%u,%u):(%lu,%*u,%lu,%*u,%lu) ",
		   &v_major, &v_index, &v_tmp[0], &v_tmp[1], &v_tmp[2]);

	    sprintf(dev_name, "dev%d-%d", v_major, v_index);
	    sdev.dk_drive      = v_tmp[0];
	    sdev.dk_drive_rblk = v_tmp[1];
	    sdev.dk_drive_wblk = v_tmp[2];
	    save_dev_stats(dev_name, curr, &sdev);

	    pos += strcspn(line + pos, " ") + 1;
	 }

	 /* Free structures corresponding to unregistered disks */
	 free_inactive_entries(iodev_nr);
      }
   }

   fclose(fp);
}