void updatexfers(int numdevs, int *devs) { register int i, j, k, t; struct statinfo stats; int num_devices = 0; u_int64_t total_transfers; if ((num_devices = devstat_getnumdevs(NULL)) < 0) { syslog(LOG_ERR, "rstatd: can't get number of devices: %s", devstat_errbuf); exit(1); } if (devstat_checkversion(NULL) < 0) { syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); exit(1); } stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); bzero(stats.dinfo, sizeof(struct devinfo)); if (devstat_getdevs(NULL, &stats) == -1) { syslog(LOG_ERR, "rstatd: can't get device list: %s", devstat_errbuf); exit(1); } for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) { if (((stats.dinfo->devices[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) && ((stats.dinfo->devices[i].device_type & DEVSTAT_TYPE_PASS) == 0)) { total_transfers = 0; for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++) total_transfers += stats.dinfo->devices[i].operations[k]; /* * XXX KDM If the total transfers for this device * are greater than the amount we can fit in a * signed integer, just set them to the maximum * amount we can fit in a signed integer. I have a * feeling that the rstat protocol assumes 32-bit * integers, so this could well break on a 64-bit * architecture like the Alpha. */ if (total_transfers > INT_MAX) t = INT_MAX; else t = total_transfers; devs[j] = t; j++; } } if (stats.dinfo->mem_ptr) free(stats.dinfo->mem_ptr); free(stats.dinfo); }
/* * Return a Python dict of tuples for disk I/O information */ static PyObject* get_disk_io_counters(PyObject* self, PyObject* args) { PyObject* py_retdict = PyDict_New(); PyObject* py_disk_info; // FIXME #if 0 int i; struct statinfo stats; if (devstat_checkversion(NULL) < 0) { Py_DECREF(py_retdict); return PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); } stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); bzero(stats.dinfo, sizeof(struct devinfo)); if (devstat_getdevs(NULL, &stats) == -1) { Py_DECREF(py_retdict); return PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed"); } for (i = 0; i < stats.dinfo->numdevs; i++) { struct devstat current; char disk_name[128]; current = stats.dinfo->devices[i]; snprintf(disk_name, sizeof(disk_name), "%s%d", current.device_name, current.unit_number); py_disk_info = Py_BuildValue("(KKKKLL)", current.operations[DEVSTAT_READ], // no reads current.operations[DEVSTAT_WRITE], // no writes current.bytes[DEVSTAT_READ], // bytes read current.bytes[DEVSTAT_WRITE], // bytes written (long long)devstat_compute_etime( ¤t.duration[DEVSTAT_READ], NULL), // r time (long long)devstat_compute_etime( ¤t.duration[DEVSTAT_WRITE], NULL) // w time ); PyDict_SetItemString(py_retdict, disk_name, py_disk_info); Py_XDECREF(py_disk_info); } if (stats.dinfo->mem_ptr) { free(stats.dinfo->mem_ptr); } free(stats.dinfo); #endif return py_retdict; }
/* * returns true if have a disk */ int haveadisk(void) { register int i; struct statinfo stats; int num_devices, retval = 0; if ((num_devices = devstat_getnumdevs(NULL)) < 0) { syslog(LOG_ERR, "rstatd: can't get number of devices: %s", devstat_errbuf); exit(1); } if (devstat_checkversion(NULL) < 0) { syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); exit(1); } stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); bzero(stats.dinfo, sizeof(struct devinfo)); if (devstat_getdevs(NULL, &stats) == -1) { syslog(LOG_ERR, "rstatd: can't get device list: %s", devstat_errbuf); exit(1); } for (i = 0; i < stats.dinfo->numdevs; i++) { if (((stats.dinfo->devices[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) && ((stats.dinfo->devices[i].device_type & DEVSTAT_TYPE_PASS) == 0)) { retval = 1; break; } } if (stats.dinfo->mem_ptr) free(stats.dinfo->mem_ptr); free(stats.dinfo); return(retval); }
void fetchiostat(void) { struct devinfo *tmp_dinfo; size_t len; len = sizeof(cur.cp_time); if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0) || len != sizeof(cur.cp_time)) { perror("kern.cp_time"); exit (1); } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; /* * Here what we want to do is refresh our device stats. * getdevs() returns 1 when the device list has changed. * If the device list has changed, we want to go through * the selection process again, in case a device that we * were previously displaying has gone away. */ switch (devstat_getdevs(NULL, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: cmdiostat("refresh", NULL); break; default: break; } num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; }
int get_diskstat(const char *devname, zbx_uint64_t *dstat) { int i; struct devstat *ds = NULL; int ret = FAIL; char dev[DEVSTAT_NAME_LEN + 10]; const char *pd; /* pointer to device name without '/dev/' prefix, e.g. 'da0' */ assert(devname); for (i = 0; i < ZBX_DSTAT_MAX; i++) dstat[i] = (zbx_uint64_t)__UINT64_C(0); if (NULL == si) { si = (struct statinfo *)zbx_malloc(si, sizeof(struct statinfo)); si->dinfo = (struct devinfo *)zbx_malloc(NULL, sizeof(struct devinfo)); memset(si->dinfo, 0, sizeof(struct devinfo)); } pd = devname; /* skip prefix ZBX_DEV_PFX, if present */ if ('\0' != *devname && 0 == strncmp(pd, ZBX_DEV_PFX, sizeof(ZBX_DEV_PFX) - 1)) pd += sizeof(ZBX_DEV_PFX) - 1; #if DEVSTAT_USER_API_VER >= 5 if (-1 == devstat_getdevs(NULL, si)) #else if (-1 == getdevs(si)) #endif return FAIL; for (i = 0; i < si->dinfo->numdevs; i++) { ds = &si->dinfo->devices[i]; /* empty '*devname' string means adding statistics for all disks together */ if ('\0' != *devname) { zbx_snprintf(dev, sizeof(dev), "%s%d", ds->device_name, ds->unit_number); if (0 != strcmp(dev, pd)) continue; } #if DEVSTAT_USER_API_VER >= 5 dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_READ]; dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_WRITE]; dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_READ]; dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_WRITE]; #else dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->num_reads; dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->num_writes; dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes_read; dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes_written; #endif ret = SUCCEED; if ('\0' != *devname) break; } return ret; }
int main(int argc, char **argv) { int c, i; int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; int count = 0, waittime = 0; char *memf = NULL, *nlistf = NULL; struct devstat_match *matches; struct itimerval alarmspec; int num_matches = 0; char errbuf[_POSIX2_LINE_MAX]; kvm_t *kd = NULL; long generation; int num_devices_specified; int num_selected, num_selections; long select_generation; char **specified_devices; devstat_select_mode select_mode; float f; int havelast = 0; matches = NULL; maxshowdevs = 3; while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) { switch(c) { case 'c': cflag++; count = atoi(optarg); if (count < 1) errx(1, "count %d is < 1", count); break; case 'C': Cflag++; break; case 'd': dflag++; break; case 'h': hflag++; break; case 'I': Iflag++; break; case 'K': Kflag++; break; case 'M': memf = optarg; break; case 'n': nflag++; maxshowdevs = atoi(optarg); if (maxshowdevs < 0) errx(1, "number of devices %d is < 0", maxshowdevs); break; case 'N': nlistf = optarg; break; case 'o': oflag++; break; case 't': tflag++; if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) errx(1, "%s", devstat_errbuf); break; case 'T': Tflag++; break; case 'w': wflag++; f = atof(optarg); waittime = f * 1000; if (waittime < 1) errx(1, "wait time is < 1ms"); break; case 'x': xflag++; break; case 'z': zflag++; break; default: usage(); exit(1); break; } } argc -= optind; argv += optind; if (nlistf != NULL || memf != NULL) { kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); if (kd == NULL) errx(1, "kvm_openfiles: %s", errbuf); if (kvm_nlist(kd, namelist) == -1) errx(1, "kvm_nlist: %s", kvm_geterr(kd)); } /* * Make sure that the userland devstat version matches the kernel * devstat version. If not, exit and print a message informing * the user of his mistake. */ if (devstat_checkversion(kd) < 0) errx(1, "%s", devstat_errbuf); /* * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is * greater than 0, they may be 0 or non-zero. */ if (dflag == 0 && xflag == 0) { Cflag = 1; Tflag = 1; } /* find out how many devices we have */ if ((num_devices = devstat_getnumdevs(kd)) < 0) err(1, "can't get number of devices"); /* * Figure out how many devices we should display. */ if (nflag == 0) { if (xflag > 0) maxshowdevs = num_devices; else if (oflag > 0) { if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) maxshowdevs = 5; else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) maxshowdevs = 5; else maxshowdevs = 4; } else { if ((dflag > 0) && (Cflag == 0)) maxshowdevs = 4; else maxshowdevs = 3; } } cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); if (cur.dinfo == NULL) err(1, "calloc failed"); last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); if (last.dinfo == NULL) err(1, "calloc failed"); /* * Grab all the devices. We don't look to see if the list has * changed here, since it almost certainly has. We only look for * errors. */ if (devstat_getdevs(kd, &cur) == -1) errx(1, "%s", devstat_errbuf); num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; /* * If the user specified any devices on the command line, see if * they are in the list of devices we have now. */ specified_devices = (char **)malloc(sizeof(char *)); if (specified_devices == NULL) err(1, "malloc failed"); for (num_devices_specified = 0; *argv; ++argv) { if (isdigit(**argv)) break; num_devices_specified++; specified_devices = (char **)realloc(specified_devices, sizeof(char *) * num_devices_specified); if (specified_devices == NULL) err(1, "realloc failed"); specified_devices[num_devices_specified - 1] = *argv; } if (nflag == 0 && maxshowdevs < num_devices_specified) maxshowdevs = num_devices_specified; dev_select = NULL; if ((num_devices_specified == 0) && (num_matches == 0)) select_mode = DS_SELECT_ADD; else select_mode = DS_SELECT_ONLY; /* * At this point, selectdevs will almost surely indicate that the * device list has changed, so we don't look for return values of 0 * or 1. If we get back -1, though, there is an error. */ if (devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, hflag) == -1) errx(1, "%s", devstat_errbuf); /* * Look for the traditional wait time and count arguments. */ if (*argv) { f = atof(*argv); waittime = f * 1000; /* Let the user know he goofed, but keep going anyway */ if (wflag != 0) warnx("discarding previous wait interval, using" " %g instead", waittime / 1000.0); wflag++; if (*++argv) { count = atoi(*argv); if (cflag != 0) warnx("discarding previous count, using %d" " instead", count); cflag++; } else count = -1; } /* * If the user specified a count, but not an interval, we default * to an interval of 1 second. */ if ((wflag == 0) && (cflag > 0)) waittime = 1 * 1000; /* * If the user specified a wait time, but not a count, we want to * go on ad infinitum. This can be redundant if the user uses the * traditional method of specifying the wait, since in that case we * already set count = -1 above. Oh well. */ if ((wflag > 0) && (cflag == 0)) count = -1; bzero(cur.cp_time, sizeof(cur.cp_time)); cur.tk_nout = 0; cur.tk_nin = 0; /* * Set the snap time to the system boot time (ie: zero), so the * stats are calculated since system boot. */ cur.snap_time = 0; /* * If the user stops the program (control-Z) and then resumes it, * print out the header again. */ (void)signal(SIGCONT, needhdr); /* * If our standard output is a tty, then install a SIGWINCH handler * and set wresized so that our first iteration through the main * iostat loop will peek at the terminal's current rows to find out * how many lines can fit in a screenful of output. */ if (isatty(fileno(stdout)) != 0) { wresized = 1; (void)signal(SIGWINCH, needresize); } else { wresized = 0; wrows = IOSTAT_DEFAULT_ROWS; } /* * Register a SIGINT handler so that we can print out final statistics * when we get that signal */ (void)signal(SIGINT, needreturn); /* * Register a SIGALRM handler to implement sleeps if the user uses the * -c or -w options */ (void)signal(SIGALRM, alarm_clock); alarmspec.it_interval.tv_sec = waittime / 1000; alarmspec.it_interval.tv_usec = 1000 * (waittime % 1000); alarmspec.it_value.tv_sec = waittime / 1000; alarmspec.it_value.tv_usec = 1000 * (waittime % 1000); setitimer(ITIMER_REAL, &alarmspec, NULL); for (headercount = 1;;) { struct devinfo *tmp_dinfo; long tmp; long double etime; sigset_t sigmask, oldsigmask; if (Tflag > 0) { if ((readvar(kd, "kern.tty_nin", X_TTY_NIN, &cur.tk_nin, sizeof(cur.tk_nin)) != 0) || (readvar(kd, "kern.tty_nout", X_TTY_NOUT, &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { Tflag = 0; warnx("disabling TTY statistics"); } } if (Cflag > 0) { if (kd == NULL) { if (readvar(kd, "kern.cp_time", 0, &cur.cp_time, sizeof(cur.cp_time)) != 0) Cflag = 0; } else { if (kvm_getcptime(kd, cur.cp_time) < 0) { warnx("kvm_getcptime: %s", kvm_geterr(kd)); Cflag = 0; } } if (Cflag == 0) warnx("disabling CPU time statistics"); } if (!--headercount) { phdr(); if (wresized != 0) doresize(); headercount = wrows; } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; /* * Here what we want to do is refresh our device stats. * devstat_getdevs() returns 1 when the device list has changed. * If the device list has changed, we want to go through * the selection process again, in case a device that we * were previously displaying has gone away. */ switch (devstat_getdevs(kd, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: { int retval; num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; retval = devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, hflag); switch(retval) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: phdr(); if (wresized != 0) doresize(); headercount = wrows; break; default: break; } break; } default: break; } /* * We only want to re-select devices if we're in 'top' * mode. This is the only mode where the devices selected * could actually change. */ if (hflag > 0) { int retval; retval = devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, hflag); switch(retval) { case -1: errx(1,"%s", devstat_errbuf); break; case 1: phdr(); if (wresized != 0) doresize(); headercount = wrows; break; default: break; } } if (Tflag > 0) { tmp = cur.tk_nin; cur.tk_nin -= last.tk_nin; last.tk_nin = tmp; tmp = cur.tk_nout; cur.tk_nout -= last.tk_nout; last.tk_nout = tmp; } etime = cur.snap_time - last.snap_time; if (etime == 0.0) etime = 1.0; for (i = 0; i < CPUSTATES; i++) { tmp = cur.cp_time[i]; cur.cp_time[i] -= last.cp_time[i]; last.cp_time[i] = tmp; } if (xflag == 0 && Tflag > 0) printf("%4.0Lf %5.0Lf", cur.tk_nin / etime, cur.tk_nout / etime); devstats(hflag, etime, havelast); if (xflag == 0) { if (Cflag > 0) cpustats(); printf("\n"); } fflush(stdout); if ((count >= 0 && --count <= 0) || return_requested) break; /* * Use sigsuspend to safely sleep until either signal is * received */ alarm_rang = 0; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGALRM); sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask); while (! (alarm_rang || return_requested) ) { sigsuspend(&oldsigmask); } sigprocmask(SIG_UNBLOCK, &sigmask, NULL); havelast = 1; } exit(0); }
sg_fs_stats *sg_get_fs_stats(int *entries){ VECTOR_DECLARE_STATIC(disk_stats, sg_fs_stats, 10, disk_stat_init, disk_stat_destroy); int num_disks=0; #if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN) || defined(HPUX) FILE *f; #endif sg_fs_stats *disk_ptr; #ifdef SOLARIS struct mnttab mp; struct statvfs fs; #endif #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) struct mntent *mp; struct statvfs fs; #endif #ifdef ALLBSD int nummnt; #ifdef HAVE_STATVFS struct statvfs *mp, **fs; #else struct statfs *mp, **fs; #endif #endif #ifdef WIN32 char lp_buf[MAX_PATH]; char volume_name_buf[BUFSIZE]; char filesys_name_buf[BUFSIZE]; char drive[4] = " :\\"; char *p; int drive_type; //@ lp_buf[0]='\0'; #endif #ifdef ALLBSD nummnt=getmntinfo(&mp, MNT_WAIT); if (nummnt<=0){ sg_set_error_with_errno(SG_ERROR_GETMNTINFO, NULL); return NULL; } for(fs = ∓ nummnt--; (*fs)++){ #endif #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) #ifdef MNT_MNTTAB if ((f=setmntent(MNT_MNTTAB, "r" ))==NULL){ #else if ((f=setmntent("/etc/mtab", "r" ))==NULL){ #endif sg_set_error(SG_ERROR_SETMNTENT, NULL); return NULL; } while((mp=getmntent(f))){ if((statvfs(mp->mnt_dir, &fs)) !=0){ continue; } #endif #ifdef SOLARIS if ((f=fopen("/etc/mnttab", "r" ))==NULL){ sg_set_error_with_errno(SG_ERROR_OPEN, "/etc/mnttab"); return NULL; } while((getmntent(f, &mp)) == 0){ if ((statvfs(mp.mnt_mountp, &fs)) !=0){ continue; } #endif #ifdef WIN32 if (!(GetLogicalDriveStringsA(BUFSIZE-1, lp_buf))) { sg_set_error(SG_ERROR_GETMNTINFO, "GetLogicalDriveStrings"); return NULL; } p = lp_buf; do { // Copy drive letter to template string *drive = *p; // Only interested in harddrives. drive_type = GetDriveTypeA(drive); if(drive_type == DRIVE_FIXED) { #else if(is_valid_fs_type(SG_MP_FSTYPENAME(mp))){ #endif if (VECTOR_RESIZE(disk_stats, num_disks + 1) < 0) { return NULL; } disk_ptr=disk_stats+num_disks; #ifndef WIN32 /* Maybe make this char[bigenough] and do strncpy's and put a null in the end? * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob * be upwards of a k each */ if (sg_update_string(&disk_ptr->device_name, SG_MP_DEVNAME(mp)) < 0) { return NULL; } if (sg_update_string(&disk_ptr->fs_type, SG_MP_FSTYPENAME(mp)) < 0) { return NULL; } if (sg_update_string(&disk_ptr->mnt_point, SG_MP_MOUNTP(mp)) < 0) { return NULL; } disk_ptr->size = SG_FS_FRSIZE(fs) * SG_FS_BLOCKS(fs); disk_ptr->avail = SG_FS_FRSIZE(fs) * SG_FS_BAVAIL(fs); disk_ptr->used = (disk_ptr->size) - (SG_FS_FRSIZE(fs) * SG_FS_BFREE(fs)); disk_ptr->total_inodes = SG_FS_FILES(fs); disk_ptr->free_inodes = SG_FS_FFREE(fs); /* Linux, FreeBSD don't have a "available" inodes */ disk_ptr->used_inodes = disk_ptr->total_inodes - disk_ptr->free_inodes; disk_ptr->avail_inodes = SG_FS_FAVAIL(fs); disk_ptr->io_size = SG_FS_BSIZE(fs); disk_ptr->block_size = SG_FS_FRSIZE(fs); disk_ptr->total_blocks = SG_FS_BLOCKS(fs); disk_ptr->free_blocks = SG_FS_BFREE(fs); disk_ptr->avail_blocks = SG_FS_BAVAIL(fs); disk_ptr->used_blocks = disk_ptr->total_blocks - disk_ptr->free_blocks; #else if(!GetVolumeInformationA(drive, volume_name_buf, BUFSIZE, NULL, NULL, NULL, filesys_name_buf, BUFSIZE)) { sg_set_error_with_errno(SG_ERROR_DISKINFO, "GetVolumeInformation"); return NULL; } if (sg_update_string(&disk_ptr->device_name, volume_name_buf) < 0) { return NULL; } if (sg_update_string(&disk_ptr->fs_type, filesys_name_buf) < 0) { return NULL; } if (sg_update_string(&disk_ptr->mnt_point, drive) < 0) { return NULL; } if (!GetDiskFreeSpaceExA(drive, NULL, (PULARGE_INTEGER)&disk_ptr->size, (PULARGE_INTEGER)&disk_ptr->avail)) { sg_set_error_with_errno(SG_ERROR_DISKINFO, "GetDiskFreeSpaceEx"); return NULL; } disk_ptr->used = disk_ptr->size - disk_ptr->avail; disk_ptr->total_inodes = 0; disk_ptr->free_inodes = 0; disk_ptr->used_inodes = 0; disk_ptr->avail_inodes = 0; /* I dunno what to do with these... so have nothing */ disk_ptr->io_size = 0; disk_ptr->block_size = 0; disk_ptr->total_blocks = 0; disk_ptr->free_blocks = 0; disk_ptr->avail_blocks = 0; disk_ptr->used_blocks = 0; #endif num_disks++; } #ifdef WIN32 while(*p++); } while(*p); #else } #endif *entries=num_disks; /* If this fails, there is very little i can do about it, so I'll ignore it :) */ #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) endmntent(f); #endif #if defined(SOLARIS) fclose(f); #endif return disk_stats; } int sg_fs_compare_device_name(const void *va, const void *vb) { const sg_fs_stats *a = (const sg_fs_stats *)va; const sg_fs_stats *b = (const sg_fs_stats *)vb; return strcmp(a->device_name, b->device_name); } int sg_fs_compare_mnt_point(const void *va, const void *vb) { const sg_fs_stats *a = (const sg_fs_stats *)va; const sg_fs_stats *b = (const sg_fs_stats *)vb; return strcmp(a->mnt_point, b->mnt_point); } static void diskio_stat_init(sg_disk_io_stats *d) { d->disk_name = NULL; } static void diskio_stat_destroy(sg_disk_io_stats *d) { free(d->disk_name); } VECTOR_DECLARE_STATIC(diskio_stats, sg_disk_io_stats, 10, diskio_stat_init, diskio_stat_destroy); #ifdef LINUX typedef struct { int major; int minor; } partition; #endif sg_disk_io_stats *sg_get_disk_io_stats(int *entries){ int num_diskio; #ifndef LINUX sg_disk_io_stats *diskio_stats_ptr; #endif #ifdef HPUX long long rbytes = 0, wbytes = 0; struct dirent *dinfo = NULL; struct stat lstatinfo; struct pst_diskinfo pstat_diskinfo[DISK_BATCH]; char fullpathbuf[1024] = {0}; dev_t diskid; DIR *dh = NULL; int diskidx = 0; int num, i; #endif #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; kstat_io_t kios; #endif #ifdef LINUX FILE *f; char *line_ptr; int major, minor; int has_pp_stats = 1; VECTOR_DECLARE_STATIC(parts, partition, 16, NULL, NULL); int i, n; time_t now; const char *format; static regex_t not_part_re, part_re; static int re_compiled = 0; #endif #if defined(FREEBSD) || defined(DFBSD) static struct statinfo stats; static int stats_init = 0; int counter; struct device_selection *dev_sel = NULL; int n_selected, n_selections; long sel_gen; struct devstat *dev_ptr; #endif #ifdef NETBSD struct disk_sysctl *stats; #endif #ifdef OPENBSD int diskcount; char *disknames, *name, *bufpp; char **dk_name; struct diskstats *stats; #endif #ifdef NETBSD #define MIBSIZE 3 #endif #ifdef OPENBSD #define MIBSIZE 2 #endif #if defined(NETBSD) || defined(OPENBSD) int num_disks, i; int mib[MIBSIZE]; size_t size; #endif #ifdef WIN32 char *name; long long rbytes; long long wbytes; #endif num_diskio=0; #ifdef HPUX while (1) { num = pstat_getdisk(pstat_diskinfo, sizeof pstat_diskinfo[0], DISK_BATCH, diskidx); if (num == -1) { sg_set_error_with_errno(SG_ERROR_PSTAT, "pstat_getdisk"); return NULL; } else if (num == 0) { break; } for (i = 0; i < num; i++) { struct pst_diskinfo *di = &pstat_diskinfo[i]; /* Skip "disabled" disks. */ if (di->psd_status == 0) { continue; } /* We can't seperate the reads from the writes, we'll * just give the same to each. (This value is in * 64-byte chunks according to the pstat header file, * and can wrap to be negative.) */ rbytes = wbytes = ((unsigned long) di->psd_dkwds) * 64LL; /* Skip unused disks. */ if (rbytes == 0 && wbytes == 0) { continue; } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; diskio_stats_ptr->systime = time(NULL); num_diskio++; /* FIXME This should use a static cache, like the Linux * code below. */ if (diskio_stats_ptr->disk_name == NULL) { dh = opendir("/dev/dsk"); if (dh == NULL) { continue; } diskid = (di->psd_dev.psd_major << 24) | di->psd_dev.psd_minor; while (1) { dinfo = readdir(dh); if (dinfo == NULL) { break; } snprintf(fullpathbuf, sizeof(fullpathbuf), "/dev/dsk/%s", dinfo->d_name); if (lstat(fullpathbuf, &lstatinfo) < 0) { continue; } if (lstatinfo.st_rdev == diskid) { if (sg_update_string(&diskio_stats_ptr->disk_name, dinfo->d_name) < 0) { return NULL; } break; } } closedir(dh); if (diskio_stats_ptr->disk_name == NULL) { if (sg_update_string(&diskio_stats_ptr->disk_name, di->psd_hw_path.psh_name) < 0) { return NULL; } } } } diskidx = pstat_diskinfo[num - 1].psd_idx + 1; } #endif #ifdef OPENBSD mib[0] = CTL_HW; mib[1] = HW_DISKCOUNT; size = sizeof(diskcount); if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKCOUNT"); return NULL; } mib[0] = CTL_HW; mib[1] = HW_DISKNAMES; if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES"); return NULL; } disknames = sg_malloc(size); if (disknames == NULL) { return NULL; } if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES"); return NULL; } dk_name = sg_malloc(diskcount * sizeof(char *)); bufpp = disknames; for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) { dk_name[i] = name; } #endif #if defined(NETBSD) || defined(OPENBSD) mib[0] = CTL_HW; mib[1] = HW_DISKSTATS; #ifdef NETBSD mib[2] = sizeof(struct disk_sysctl); #endif if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS"); return NULL; } #ifdef NETBSD num_disks = size / sizeof(struct disk_sysctl); #else num_disks = size / sizeof(struct diskstats); #endif stats = sg_malloc(size); if (stats == NULL) { return NULL; } if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS"); return NULL; } for (i = 0; i < num_disks; i++) { const char *name; u_int64_t rbytes, wbytes; #ifdef NETBSD #ifdef HAVE_DK_RBYTES rbytes = stats[i].dk_rbytes; wbytes = stats[i].dk_wbytes; #else /* Before 2.0, NetBSD merged reads and writes. */ rbytes = wbytes = stats[i].dk_bytes; #endif #else #ifdef HAVE_DS_RBYTES rbytes = stats[i].ds_rbytes; wbytes = stats[i].ds_wbytes; #else /* Before 3.5, OpenBSD merged reads and writes */ rbytes = wbytes = stats[i].ds_bytes; #endif #endif /* Don't keep stats for disks that have never been used. */ if (rbytes == 0 && wbytes == 0) { continue; } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; #ifdef NETBSD name = stats[i].dk_name; #else name = dk_name[i]; #endif if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) { return NULL; } diskio_stats_ptr->systime = time(NULL); num_diskio++; } free(stats); #ifdef OPENBSD free(dk_name); free(disknames); #endif #endif #if defined(FREEBSD) || defined(DFBSD) if (!stats_init) { stats.dinfo=sg_malloc(sizeof(struct devinfo)); if(stats.dinfo==NULL) return NULL; bzero(stats.dinfo, sizeof(struct devinfo)); stats_init = 1; } #ifdef FREEBSD5 if ((devstat_getdevs(NULL, &stats)) < 0) { /* FIXME devstat functions return a string error in devstat_errbuf */ sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL); return NULL; } /* Not aware of a get all devices, so i said 999. If we ever * find a machine with more than 999 disks, then i'll change * this number :) */ if (devstat_selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) { sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL); return NULL; } #else if ((getdevs(&stats)) < 0) { sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL); return NULL; } /* Not aware of a get all devices, so i said 999. If we ever * find a machine with more than 999 disks, then i'll change * this number :) */ if (selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) { sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL); return NULL; } #endif for(counter=0;counter<stats.dinfo->numdevs;counter++){ dev_ptr=&stats.dinfo->devices[dev_sel[counter].position]; /* Throw away devices that have done nothing, ever.. Eg "odd" * devices.. like mem, proc.. and also doesn't report floppy * drives etc unless they are doing stuff :) */ #ifdef FREEBSD5 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue; #else if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue; #endif if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr=diskio_stats+num_diskio; #ifdef FREEBSD5 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ]; diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE]; #else diskio_stats_ptr->read_bytes=dev_ptr->bytes_read; diskio_stats_ptr->write_bytes=dev_ptr->bytes_written; #endif if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name); if (asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number) == -1) { sg_set_error_with_errno(SG_ERROR_ASPRINTF, NULL); return NULL; } diskio_stats_ptr->systime=time(NULL); num_diskio++; } free(dev_sel); #endif #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (!strcmp(ksp->ks_class, "disk")) { if(ksp->ks_type != KSTAT_TYPE_IO) continue; /* We dont want metadevices appearins as num_diskio */ if(strcmp(ksp->ks_module, "md")==0) continue; if((kstat_read(kc, ksp, &kios))==-1){ } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { kstat_close(kc); return NULL; } diskio_stats_ptr=diskio_stats+num_diskio; diskio_stats_ptr->read_bytes=kios.nread; diskio_stats_ptr->write_bytes=kios.nwritten; if (sg_update_string(&diskio_stats_ptr->disk_name, sg_get_svr_from_bsd(ksp->ks_name)) < 0) { kstat_close(kc); return NULL; } diskio_stats_ptr->systime=time(NULL); num_diskio++; } } kstat_close(kc); #endif #ifdef LINUX num_diskio = 0; n = 0; /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels have statistics in here too, so we can use those directly. 2.6 kernels have /proc/diskstats instead with almost (but not quite) the same format. */ f = fopen("/proc/diskstats", "r"); format = " %d %d %99s %*d %*d %lld %*d %*d %*d %lld"; if (f == NULL) { f = fopen("/proc/partitions", "r"); format = " %d %d %*d %99s %*d %*d %lld %*d %*d %*d %lld"; } if (f == NULL) goto out; now = time(NULL); if (!re_compiled) { if (regcomp(&part_re, "^(.*/)?[^/]*[0-9]$", REG_EXTENDED | REG_NOSUB) != 0) { sg_set_error(SG_ERROR_PARSE, NULL); goto out; } if (regcomp(¬_part_re, "^(.*/)?[^/0-9]+[0-9]+d[0-9]+$", REG_EXTENDED | REG_NOSUB) != 0) { sg_set_error(SG_ERROR_PARSE, NULL); goto out; } re_compiled = 1; } while ((line_ptr = sg_f_read_line(f, "")) != NULL) { char name[100]; long long rsect, wsect; int nr = sscanf(line_ptr, format, &major, &minor, name, &rsect, &wsect); if (nr < 3) continue; /* Skip device names ending in numbers, since they're partitions, unless they match the c0d0 pattern that some RAID devices use. */ /* FIXME: For 2.6+, we should probably be using sysfs to detect this... */ if ((regexec(&part_re, name, 0, NULL, 0) == 0) && (regexec(¬_part_re, name, 0, NULL, 0) != 0)) { continue; } if (nr < 5) { has_pp_stats = 0; rsect = 0; wsect = 0; } if (VECTOR_RESIZE(diskio_stats, n + 1) < 0) { goto out; } if (VECTOR_RESIZE(parts, n + 1) < 0) { goto out; } if (sg_update_string(&diskio_stats[n].disk_name, name) < 0) { goto out; } diskio_stats[n].read_bytes = rsect * 512; diskio_stats[n].write_bytes = wsect * 512; diskio_stats[n].systime = now; parts[n].major = major; parts[n].minor = minor; n++; } fclose(f); f = NULL; if (!has_pp_stats) { /* This is an older kernel where /proc/partitions doesn't contain stats. Read what we can from /proc/stat instead, and fill in the appropriate bits of the list allocated above. */ f = fopen("/proc/stat", "r"); if (f == NULL) goto out; now = time(NULL); line_ptr = sg_f_read_line(f, "disk_io:"); if (line_ptr == NULL) goto out; while((line_ptr=strchr(line_ptr, ' '))!=NULL){ long long rsect, wsect; if (*++line_ptr == '\0') break; if((sscanf(line_ptr, "(%d,%d):(%*d, %*d, %lld, %*d, %lld)", &major, &minor, &rsect, &wsect)) != 4) { continue; } /* Find the corresponding device from earlier. Just to add to the fun, "minor" is actually the disk number, not the device minor, so we need to figure out the real minor number based on the major! This list is not exhaustive; if you're running an older kernel you probably don't have fancy I2O hardware anyway... */ switch (major) { case 3: case 21: case 22: case 33: case 34: case 36: case 56: case 57: case 88: case 89: case 90: case 91: minor *= 64; break; case 9: case 43: break; default: minor *= 16; break; } for (i = 0; i < n; i++) { if (major == parts[i].major && minor == parts[i].minor) break; } if (i == n) continue; /* We read the number of blocks. Blocks are stored in 512 bytes */ diskio_stats[i].read_bytes = rsect * 512; diskio_stats[i].write_bytes = wsect * 512; diskio_stats[i].systime = now; } } num_diskio = n; out: if (f != NULL) fclose(f); #endif #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #endif #ifdef WIN32 sg_set_error(SG_ERROR_NONE, NULL); while((name = get_diskio(num_diskio, &rbytes, &wbytes)) != NULL) { if (VECTOR_RESIZE(diskio_stats, num_diskio+1)) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) { return NULL; } sg_update_string(&name, NULL); diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; diskio_stats_ptr->systime = 0; num_diskio++; } #endif *entries=num_diskio; return diskio_stats; } sg_disk_io_stats *sg_get_disk_io_stats_diff(int *entries){ #ifndef WIN32 VECTOR_DECLARE_STATIC(diff, sg_disk_io_stats, 1, diskio_stat_init, diskio_stat_destroy); sg_disk_io_stats *src = NULL, *dest; int i, j, diff_count, new_count; if (diskio_stats == NULL) { /* No previous stats, so we can't calculate a difference. */ return sg_get_disk_io_stats(entries); } /* Resize the results array to match the previous stats. */ diff_count = VECTOR_SIZE(diskio_stats); if (VECTOR_RESIZE(diff, diff_count) < 0) { return NULL; } /* Copy the previous stats into the result. */ for (i = 0; i < diff_count; i++) { src = &diskio_stats[i]; dest = &diff[i]; if (sg_update_string(&dest->disk_name, src->disk_name) < 0) { return NULL; } dest->read_bytes = src->read_bytes; dest->write_bytes = src->write_bytes; dest->systime = src->systime; } /* Get a new set of stats. */ if (sg_get_disk_io_stats(&new_count) == NULL) { return NULL; } /* For each previous stat... */ for (i = 0; i < diff_count; i++) { dest = &diff[i]; /* ... find the corresponding new stat ... */ for (j = 0; j < new_count; j++) { /* Try the new stat in the same position first, since that's most likely to be it. */ src = &diskio_stats[(i + j) % new_count]; if (strcmp(src->disk_name, dest->disk_name) == 0) { break; } } if (j == new_count) { /* No match found. */ continue; } /* ... and subtract the previous stat from it to get the difference. */ dest->read_bytes = src->read_bytes - dest->read_bytes; dest->write_bytes = src->write_bytes - dest->write_bytes; dest->systime = src->systime - dest->systime; } *entries = diff_count; return diff; #else /* WIN32 */ return sg_get_disk_io_stats(entries); #endif } int sg_disk_io_compare_name(const void *va, const void *vb) { const sg_disk_io_stats *a = (const sg_disk_io_stats *)va; const sg_disk_io_stats *b = (const sg_disk_io_stats *)vb; return strcmp(a->disk_name, b->disk_name); }
static void dovmstat(unsigned int interval, int reps) { struct vmtotal total; time_t uptime, halfuptime; struct devinfo *tmp_dinfo; size_t size; int ncpus, maxid; u_long cpumask; int rate_adj; uptime = getuptime() / 1000000000LL; halfuptime = uptime / 2; rate_adj = 1; ncpus = 1; maxid = 0; /* * If the user stops the program (control-Z) and then resumes it, * print out the header again. */ (void)signal(SIGCONT, needhdr); /* * If our standard output is a tty, then install a SIGWINCH handler * and set wresized so that our first iteration through the main * vmstat loop will peek at the terminal's current rows to find out * how many lines can fit in a screenful of output. */ if (isatty(fileno(stdout)) != 0) { wresized = 1; (void)signal(SIGWINCH, needresize); } else { wresized = 0; winlines = VMSTAT_DEFAULT_LINES; } if (kd != NULL) { if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) kread(X_STATHZ, &hz, sizeof(hz)); if (!hz) kread(X_HZ, &hz, sizeof(hz)); } else { struct clockinfo clockrate; size = sizeof(clockrate); mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); if (size != sizeof(clockrate)) errx(1, "clockrate size mismatch"); hz = clockrate.hz; } if (Pflag) { ncpus = getcpuinfo(&cpumask, &maxid); size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; cur_cp_times = calloc(1, size_cp_times); last_cp_times = calloc(1, size_cp_times); } for (hdrcnt = 1;;) { if (!--hdrcnt) printhdr(maxid, cpumask); if (kd != NULL) { if (kvm_getcptime(kd, cur.cp_time) < 0) errx(1, "kvm_getcptime: %s", kvm_geterr(kd)); } else { size = sizeof(cur.cp_time); mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); if (size != sizeof(cur.cp_time)) errx(1, "cp_time size mismatch"); } if (Pflag) { size = size_cp_times; mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); if (size != size_cp_times) errx(1, "cp_times mismatch"); } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; /* * Here what we want to do is refresh our device stats. * getdevs() returns 1 when the device list has changed. * If the device list has changed, we want to go through * the selection process again, in case a device that we * were previously displaying has gone away. */ switch (devstat_getdevs(NULL, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: { int retval; num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; retval = devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, 0); switch (retval) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: printhdr(maxid, cpumask); break; default: break; } } default: break; } fill_vmmeter(&sum); fill_vmtotal(&total); (void)printf("%1d %1d %1d", total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); #define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) #define rate(x) (((x) * rate_adj + halfuptime) / uptime) /* round */ if (hflag) { printf(""); prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 5); printf(" "); prthuman(total.t_free * (u_int64_t)sum.v_page_size, 5); printf(" "); (void)printf("%5lu ", (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); } else { printf(" %7d", vmstat_pgtok(total.t_avm)); printf(" %7d ", vmstat_pgtok(total.t_free)); (void)printf("%4lu ", (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); } (void)printf("%3lu ", (unsigned long)rate(sum.v_reactivated - osum.v_reactivated)); (void)printf("%3lu ", (unsigned long)rate(sum.v_swapin + sum.v_vnodein - (osum.v_swapin + osum.v_vnodein))); (void)printf("%3lu ", (unsigned long)rate(sum.v_swapout + sum.v_vnodeout - (osum.v_swapout + osum.v_vnodeout))); (void)printf("%5lu ", (unsigned long)rate(sum.v_tfree - osum.v_tfree)); (void)printf("%4lu ", (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); devstats(); (void)printf("%4lu %5lu %5lu", (unsigned long)rate(sum.v_intr - osum.v_intr), (unsigned long)rate(sum.v_syscall - osum.v_syscall), (unsigned long)rate(sum.v_swtch - osum.v_swtch)); if (Pflag) pcpustats(ncpus, cpumask, maxid); else cpustats(); (void)printf("\n"); (void)fflush(stdout); if (reps >= 0 && --reps <= 0) break; osum = sum; uptime = interval; rate_adj = 1000; /* * We round upward to avoid losing low-frequency events * (i.e., >= 1 per interval but < 1 per millisecond). */ if (interval != 1) halfuptime = (uptime + 1) / 2; else halfuptime = 0; (void)usleep(interval * 1000); } }
PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { int i; struct statinfo stats; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; if (devstat_checkversion(NULL) < 0) { PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); goto error; } stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); if (stats.dinfo == NULL) { PyErr_NoMemory(); goto error; } bzero(stats.dinfo, sizeof(struct devinfo)); if (devstat_getdevs(NULL, &stats) == -1) { PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed"); goto error; } for (i = 0; i < stats.dinfo->numdevs; i++) { py_disk_info = NULL; struct devstat current; char disk_name[128]; current = stats.dinfo->devices[i]; snprintf(disk_name, sizeof(disk_name), "%s%d", current.device_name, current.unit_number); py_disk_info = Py_BuildValue( "(KKKKLLL)", current.operations[DEVSTAT_READ], // no reads current.operations[DEVSTAT_WRITE], // no writes current.bytes[DEVSTAT_READ], // bytes read current.bytes[DEVSTAT_WRITE], // bytes written (long long) PSUTIL_BT2MSEC(current.duration[DEVSTAT_READ]), // r time (long long) PSUTIL_BT2MSEC(current.duration[DEVSTAT_WRITE]), // w time (long long) PSUTIL_BT2MSEC(current.busy_time) // busy time ); // finished transactions if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } if (stats.dinfo->mem_ptr) free(stats.dinfo->mem_ptr); free(stats.dinfo); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (stats.dinfo != NULL) free(stats.dinfo); return NULL; }
static void getinfo(struct Info *ls) { struct devinfo *tmp_dinfo; size_t size; int mib[2]; GETSYSCTL("kern.cp_time", ls->time); GETSYSCTL("kern.cp_time", cur.cp_time); GETSYSCTL("vm.stats.sys.v_swtch", ls->v_swtch); GETSYSCTL("vm.stats.sys.v_trap", ls->v_trap); GETSYSCTL("vm.stats.sys.v_syscall", ls->v_syscall); GETSYSCTL("vm.stats.sys.v_intr", ls->v_intr); GETSYSCTL("vm.stats.sys.v_soft", ls->v_soft); GETSYSCTL("vm.stats.vm.v_vm_faults", ls->v_vm_faults); GETSYSCTL("vm.stats.vm.v_io_faults", ls->v_io_faults); GETSYSCTL("vm.stats.vm.v_cow_faults", ls->v_cow_faults); GETSYSCTL("vm.stats.vm.v_zfod", ls->v_zfod); GETSYSCTL("vm.stats.vm.v_ozfod", ls->v_ozfod); GETSYSCTL("vm.stats.vm.v_swapin", ls->v_swapin); GETSYSCTL("vm.stats.vm.v_swapout", ls->v_swapout); GETSYSCTL("vm.stats.vm.v_swappgsin", ls->v_swappgsin); GETSYSCTL("vm.stats.vm.v_swappgsout", ls->v_swappgsout); GETSYSCTL("vm.stats.vm.v_vnodein", ls->v_vnodein); GETSYSCTL("vm.stats.vm.v_vnodeout", ls->v_vnodeout); GETSYSCTL("vm.stats.vm.v_vnodepgsin", ls->v_vnodepgsin); GETSYSCTL("vm.stats.vm.v_vnodepgsout", ls->v_vnodepgsout); GETSYSCTL("vm.stats.vm.v_intrans", ls->v_intrans); GETSYSCTL("vm.stats.vm.v_reactivated", ls->v_reactivated); GETSYSCTL("vm.stats.vm.v_pdwakeups", ls->v_pdwakeups); GETSYSCTL("vm.stats.vm.v_pdpages", ls->v_pdpages); GETSYSCTL("vm.stats.vm.v_dfree", ls->v_dfree); GETSYSCTL("vm.stats.vm.v_pfree", ls->v_pfree); GETSYSCTL("vm.stats.vm.v_tfree", ls->v_tfree); GETSYSCTL("vm.stats.vm.v_page_size", ls->v_page_size); GETSYSCTL("vm.stats.vm.v_free_count", ls->v_free_count); GETSYSCTL("vm.stats.vm.v_wire_count", ls->v_wire_count); GETSYSCTL("vm.stats.vm.v_active_count", ls->v_active_count); GETSYSCTL("vm.stats.vm.v_inactive_count", ls->v_inactive_count); GETSYSCTL("vfs.bufspace", ls->bufspace); GETSYSCTL("kern.maxvnodes", ls->desiredvnodes); GETSYSCTL("vfs.numvnodes", ls->numvnodes); GETSYSCTL("vfs.freevnodes", ls->freevnodes); GETSYSCTL("vfs.cache.nchstats", ls->nchstats); GETSYSCTL("vfs.numdirtybuffers", ls->numdirtybuffers); GETSYSCTL("vm.kmem_map_size", ls->v_kmem_map_size); getsysctl("hw.intrcnt", ls->intrcnt, nintr * sizeof(u_long)); size = sizeof(ls->Total); mib[0] = CTL_VM; mib[1] = VM_TOTAL; if (sysctl(mib, 2, &ls->Total, &size, NULL, 0) < 0) { error("Can't get kernel info: %s\n", strerror(errno)); bzero(&ls->Total, sizeof(ls->Total)); } size = sizeof(ncpu); if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0 || size != sizeof(ncpu)) ncpu = 1; tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; switch (devstat_getdevs(NULL, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; cmdkre("refresh", NULL); break; default: break; } }
int cmdkre(const char *cmd, const char *args) { int retval; if (prefix(cmd, "run")) { retval = 1; copyinfo(&s2, &s1); switch (devstat_getdevs(NULL, &run)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = run.dinfo->numdevs; generation = run.dinfo->generation; retval = dscmd("refresh", NULL, MAXDRIVES, &cur); if (retval == 2) labelkre(); break; default: break; } state = RUN; return (retval); } if (prefix(cmd, "boot")) { state = BOOT; copyinfo(&z, &s1); return (1); } if (prefix(cmd, "time")) { state = TIME; return (1); } if (prefix(cmd, "zero")) { retval = 1; if (state == RUN) { getinfo(&s1); switch (devstat_getdevs(NULL, &run)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = run.dinfo->numdevs; generation = run.dinfo->generation; retval = dscmd("refresh",NULL, MAXDRIVES, &cur); if (retval == 2) labelkre(); break; default: break; } } return (retval); } retval = dscmd(cmd, args, MAXDRIVES, &cur); if (retval == 2) labelkre(); return(retval); }