void fetchiostat(void) { struct devinfo *tmp_dinfo; if (kinfo_get_sched_cputime(&cp_time)) err(1, "kinfo_get_sched_cputime"); tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.busy_time = cur.busy_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 (getdevs(&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; }
void updatexfers(int numdevs, int *devs) { register int i, j, t; struct statinfo stats; int num_devices = 0; u_int64_t total_transfers; if ((num_devices = getnumdevs()) < 0) { syslog(LOG_ERR, "rstatd: can't get number of devices: %s", devstat_errbuf); exit(1); } if (checkversion() < 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 (getdevs(&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 = stats.dinfo->devices[i].num_reads + stats.dinfo->devices[i].num_writes + stats.dinfo->devices[i].num_other; /* * 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); }
void gkrellm_sys_disk_read_data(void) { int ndevs; int num_selected; int num_selections; int maxshowdevs = 10; struct device_selection *dev_select = NULL; long select_generation; int dn; gchar name[32]; if (getdevs(&statinfo_cur) < 0) return; ndevs = statinfo_cur.dinfo->numdevs; if (selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, statinfo_cur.dinfo->generation, statinfo_cur.dinfo->devices, ndevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, maxshowdevs, 1) >= 0) { for (dn = 0; dn < ndevs; ++dn) { int di; struct devstat *dev; // int block_size; // int blocks_read, blocks_written; di = dev_select[dn].position; dev = &statinfo_cur.dinfo->devices[di]; // block_size = (dev->block_size > 0) // ? dev->block_size : 512; // blocks_read = dev->bytes_read / block_size; // blocks_written = dev->bytes_written / block_size; /* to use gkrellm_disk_assign_data_by_device() would need gkrellm_sys_disk_name_from_device() implemented */ snprintf(name, sizeof(name), "%s%d", dev->device_name, dev->unit_number); gkrellm_disk_assign_data_by_name(name, dev->bytes_read, dev->bytes_written, FALSE); } free(dev_select); } }
/* * returns true if have a disk */ int haveadisk(void) { register int i; struct statinfo stats; int num_devices, retval = 0; if ((num_devices = getnumdevs()) < 0) { syslog(LOG_ERR, "rstatd: can't get number of devices: %s", devstat_errbuf); exit(1); } if (checkversion() < 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 (getdevs(&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); }
int br_getunit(char *arg, int *house, int *devs) { /* * Get units to be accessed from the command line in native BottleRocket style */ if (strlen(arg) < 2) { errno = EINVAL; return -1; } if ((*devs = getdevs(arg + 1)) < 0) return -1; *(arg + 1) = '\0'; if ((*house = gethouse(arg)) < 0) return -1; return 0; }
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; }
static void getinfo(struct Info *ls) { struct devinfo *tmp_dinfo; struct nchstats *nch_tmp; size_t size; size_t vms_size = sizeof(ls->Vms); size_t vmm_size = sizeof(ls->Vmm); size_t nch_size = sizeof(ls->nchstats) * SMP_MAXCPU; if (sysctlbyname("vm.vmstats", &ls->Vms, &vms_size, NULL, 0)) { perror("sysctlbyname: vm.vmstats"); exit(1); } if (sysctlbyname("vm.vmmeter", &ls->Vmm, &vmm_size, NULL, 0)) { perror("sysctlbyname: vm.vmstats"); exit(1); } if (kinfo_get_sched_cputime(&ls->cp_time)) err(1, "kinfo_get_sched_cputime"); if (kinfo_get_sched_cputime(&cp_time)) err(1, "kinfo_get_sched_cputime"); NREAD(X_BUFFERSPACE, &ls->bufspace, sizeof(ls->bufspace)); NREAD(X_DESIREDVNODES, &ls->desiredvnodes, sizeof(ls->desiredvnodes)); NREAD(X_NUMVNODES, &ls->numvnodes, sizeof(ls->numvnodes)); NREAD(X_FREEVNODES, &ls->freevnodes, sizeof(ls->freevnodes)); NREAD(X_NUMDIRTYBUFFERS, &ls->dirtybufspace, sizeof(ls->dirtybufspace)); if (nintr) { size = nintr * sizeof(ls->intrcnt[0]); sysctlbyname("hw.intrcnt_all", ls->intrcnt, &size, NULL, 0); } size = sizeof(ls->Total); if (sysctlbyname("vm.vmtotal", &ls->Total, &size, NULL, 0) < 0) { error("Can't get kernel info: %s\n", strerror(errno)); bzero(&ls->Total, sizeof(ls->Total)); } if ((nch_tmp = malloc(nch_size)) == NULL) { perror("malloc"); exit(1); } else { if (sysctlbyname("vfs.cache.nchstats", nch_tmp, &nch_size, NULL, 0)) { perror("sysctlbyname vfs.cache.nchstats"); free(nch_tmp); exit(1); } else { if ((nch_tmp = realloc(nch_tmp, nch_size)) == NULL) { perror("realloc"); exit(1); } } } if (kinfo_get_cpus(&ncpu)) err(1, "kinfo_get_cpus"); kvm_nch_cpuagg(nch_tmp, &ls->nchstats, ncpu); free(nch_tmp); tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.busy_time = cur.busy_time; switch (getdevs(&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, char *args) { int retval; if (prefix(cmd, "run")) { retval = 1; copyinfo(&s2, &s1); switch (getdevs(&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 (getdevs(&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); }
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); }
int main(int argc, char **argv) { char *port_source = "at compile time"; char *tmp_port; int opt; int house = 0; int repeat; int devs; int dimlevel = 0; br_control_info *cinfo = NULL; int tmperrno; #ifdef HAVE_GETOPT_LONG int opt_index; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"port", required_argument, 0, 'x'}, {"repeat", required_argument, 0, 'r'}, {"on", required_argument, 0, 'n'}, {"off", required_argument, 0, 'f'}, {"ON", no_argument, 0, 'N'}, {"OFF", no_argument, 0, 'F'}, {"dim", required_argument, 0, 'd'}, {"lamps_on", no_argument, 0, 'B'}, {"lamps_off", no_argument, 0, 'D'}, {"inverse", no_argument, 0, 'i'}, {"house", required_argument, 0, 'c'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} }; #endif #define OPT_STRING "x:hvr:ic:n:Nf:Fd:BD" /* * It's possible to do an exec without even passing argv[0]; * this is just to make sure we don't make any bad * output decisions without accounting for that */ if (argc) MyName = argv[0]; if (argc < 2) { usage(); exit(EINVAL); } if ((cinfo = malloc(sizeof(br_control_info))) == NULL) { tmperrno = errno; fprintf(stderr, "%s: Error (%s) allocating memory.\n", MyName, strerror(errno)); exit(tmperrno); } CINFO_CLR(cinfo); cinfo->port = X10_PORTNAME; cinfo->repeat = 1; if ((tmp_port = getenv("X10_PORTNAME"))) { port_source = "in the environment variable X10_PORTNAME"; if (!checkimmutableport(port_source)) cinfo->port = tmp_port; } #ifdef HAVE_GETOPT_LONG while ((opt = getopt_long(argc, argv, OPT_STRING, long_options, &opt_index)) != -1) { #else while ((opt = getopt(argc, argv, OPT_STRING)) != -1) { #endif switch (opt) { case 'x': port_source = "on the command line"; if (checkimmutableport(port_source) < 0) exit(errno); cinfo->port = optarg; break; case 'r': repeat = atoi(optarg); if (!repeat && !isdigit(*optarg)) { fprintf(stderr, "%s: Invalid repeat value specified.\n", MyName); exit(EINVAL); } cinfo->repeat = (repeat ? repeat:INT_MAX); break; case 'v': if (Verbose++ == 10) fprintf(stderr, "\nGet a LIFE already. " "I've got enough v's, thanks.\n\n"); break; case 'i': cinfo->inverse++; /* no this isn't documented. * your free gift for reading the source. */ break; case 'c': if ((house = gethouse(optarg)) < 0) exit(errno); break; case 'n': if ((devs = getdevs(optarg)) < 0) exit(errno); if (addcmd(cinfo, ON, house, devs, 0) < 0) exit(errno); break; case 'N': if (addcmd(cinfo, ALL_ON, house, 0, 0) < 0) exit(errno); break; case 'f': if ((devs = getdevs(optarg)) < 0) exit(errno); if (addcmd(cinfo, OFF, house, devs, 0) < 0) exit(errno); break; case 'F': if (addcmd(cinfo, ALL_OFF, house, 0, 0) < 0) exit(errno); break; case 'd': if ((devs = getdim(optarg, &dimlevel)) < 0) exit(errno); if (addcmd(cinfo, DIM, house, devs, dimlevel) < 0) exit(errno); break; case 'B': if (addcmd(cinfo, ALL_LAMPS_ON, house, 0, 0) < 0) exit(errno); break; case 'D': if (addcmd(cinfo, ALL_LAMPS_OFF, house, 0, 0) < 0) exit(errno); break; case 'h': usage(); exit(0); default: usage(); exit(EINVAL); } } if (argc > optind) { /* * Must be using the native BottleRocket command line... */ if (native_br(cinfo, argc, argv, optind) < 0) exit(errno); } if (open_port(cinfo) < 0) exit(errno); if (br_execute(cinfo) < 0) exit(errno); if (close_port(cinfo) < 0) exit(errno); free(cinfo); return 0; }
static void dovmstat(u_int interval, int reps) { struct vmtotal total; struct devinfo *tmp_dinfo; size_t vmm_size = sizeof(vmm); size_t vms_size = sizeof(vms); size_t vmt_size = sizeof(total); int initial = 1; signal(SIGCONT, needhdr); for (hdrcnt = 1;;) { if (!--hdrcnt) printhdr(); if (kinfo_get_sched_cputime(&cp_time)) err(1, "kinfo_get_sched_cputime"); tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.busy_time = cur.busy_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 (getdevs(&cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: { int retval; num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; retval = 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(); break; default: break; } } default: break; } if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0)) { perror("sysctlbyname: vm.vmstats"); exit(1); } if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) { perror("sysctlbyname: vm.vmmeter"); exit(1); } if (sysctlbyname("vm.vmtotal", &total, &vmt_size, NULL, 0)) { perror("sysctlbyname: vm.vmtotal"); exit(1); } printf("%2ld %1ld %1ld", total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); #define vmstat_pgtok(a) \ (intmax_t)(((intmax_t)(a) * vms.v_page_size) >> 10) #define rate(x) \ (intmax_t)(initial ? (x) : ((intmax_t)(x) * 1000 + interval / 2) \ / interval) printf(" %7jd %6jd ", vmstat_pgtok(total.t_avm), vmstat_pgtok(total.t_free)); printf("%4ju ", rate(vmm.v_vm_faults - ovmm.v_vm_faults)); printf("%3ju ", rate(vmm.v_reactivated - ovmm.v_reactivated)); printf("%3ju ", rate(vmm.v_swapin + vmm.v_vnodein - (ovmm.v_swapin + ovmm.v_vnodein))); printf("%3ju ", rate(vmm.v_swapout + vmm.v_vnodeout - (ovmm.v_swapout + ovmm.v_vnodeout))); printf("%3ju ", rate(vmm.v_tfree - ovmm.v_tfree)); printf("%3ju ", rate(vmm.v_pdpages - ovmm.v_pdpages)); devstats(); printf("%4ju %4ju %3ju ", rate(vmm.v_intr - ovmm.v_intr), rate(vmm.v_syscall - ovmm.v_syscall), rate(vmm.v_swtch - ovmm.v_swtch)); cpustats(); printf("\n"); fflush(stdout); if (reps >= 0 && --reps <= 0) break; ovmm = vmm; usleep(interval * 1000); initial = 0; } }