2 * Conky, a system monitor, based on torsmo
4 * Any original torsmo code is licensed under the BSD license
6 * All code written since the fork of torsmo is licensed under the GPL
8 * Please see COPYING for details
10 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
11 * Copyright (c) 2005-2008 Brenden Matthews, Philip Kovacs, et. al.
13 * All rights reserved.
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 /* The following ifdefs were adapted from gkrellm */
32 #include <linux/major.h>
34 #if !defined(MD_MAJOR)
38 #if !defined(LVM_BLK_MAJOR)
39 #define LVM_BLK_MAJOR 58
42 #if !defined(NBD_MAJOR)
46 static struct diskio_stat diskio_stats_[MAX_DISKIO_STATS];
47 struct diskio_stat *diskio_stats = diskio_stats_;
49 void clear_diskio_stats(void)
52 for(i = 0; i < MAX_DISKIO_STATS; i++) {
53 if (diskio_stats[i].dev) {
54 free(diskio_stats[i].dev);
55 diskio_stats[i].dev = 0;
60 struct diskio_stat *prepare_diskio_stat(const char *s)
62 struct diskio_stat *new = 0;
66 char device[text_buffer_size], fbuf[text_buffer_size];
68 /* lookup existing or get new */
69 for (i = 0; i < MAX_DISKIO_STATS; i++) {
70 if (diskio_stats[i].dev) {
71 if (strcmp(diskio_stats[i].dev, s) == 0) {
72 return &diskio_stats[i];
75 new = &diskio_stats[i];
81 ERR("too many diskio stats");
88 new->dev = strndup(s, text_buffer_size);
91 * check that device actually exists
94 if (!(fp = open_file("/proc/diskstats", &rep))) {
95 ERR("cannot read from /proc/diskstats");
100 fgets(fbuf, text_buffer_size, fp);
101 if (sscanf(fbuf, "%*u %*u %255s %*u %*u %*u %*u %*u %*u %*u", device)) {
102 // check for device match
103 if (strncmp(new->dev, device, 256) == 0) {
112 ERR("diskio device '%s' does not exist", s);
116 new->current_read = 0;
117 new ->current_write = 0;
118 new->last = UINT_MAX;
119 new->last_read = UINT_MAX;
120 new->last_write = UINT_MAX;
124 void update_diskio(void)
126 static unsigned int last = UINT_MAX;
127 static unsigned int last_read = UINT_MAX;
128 static unsigned int last_write = UINT_MAX;
132 char buf[512], devbuf[64];
134 unsigned int major, minor;
135 unsigned int current = 0;
136 unsigned int current_read = 0;
137 unsigned int current_write = 0;
138 unsigned int reads, writes = 0;
140 int tot, tot_read, tot_write;
142 if (!(fp = open_file("/proc/diskstats", &rep))) {
143 info.diskio_value = 0;
147 /* read reads and writes from all disks (minor = 0), including cd-roms
148 * and floppies, and sum them up */
151 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
152 &minor, devbuf, &reads, &writes);
153 /* ignore subdevices (they have only 3 matching entries in their line)
154 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
156 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
157 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
158 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
159 current += reads + writes;
160 current_read += reads;
161 current_write += writes;
163 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
164 &major, &minor, devbuf, &reads, &writes);
165 if (col_count != 5) {
169 for (i = 0; i < MAX_DISKIO_STATS; i++) {
170 if (diskio_stats[i].dev &&
171 strncmp(devbuf, diskio_stats[i].dev, text_buffer_size) == 0) {
172 diskio_stats[i].current =
173 (reads + writes - diskio_stats[i].last) / 2;
174 diskio_stats[i].current_read =
175 (reads - diskio_stats[i].last_read) / 2;
176 diskio_stats[i].current_write =
177 (writes - diskio_stats[i].last_write) / 2;
178 if (reads + writes < diskio_stats[i].last) {
179 diskio_stats[i].current = 0;
181 if (reads < diskio_stats[i].last_read) {
182 diskio_stats[i].current_read = 0;
183 diskio_stats[i].current = diskio_stats[i].current_write;
185 if (writes < diskio_stats[i].last_write) {
186 diskio_stats[i].current_write = 0;
187 diskio_stats[i].current = diskio_stats[i].current_read;
189 diskio_stats[i].last = reads + writes;
190 diskio_stats[i].last_read = reads;
191 diskio_stats[i].last_write = writes;
196 /* since the values in /proc/diststats are absolute, we have to substract
197 * our last reading. The numbers stand for "sectors read", and we therefore
198 * have to divide by two to get KB */
199 tot = ((double) (current - last) / 2);
200 tot_read = ((double) (current_read - last_read) / 2);
201 tot_write = ((double) (current_write - last_write) / 2);
203 if (last_read > current_read) {
206 if (last_write > current_write) {
210 if (last > current) {
211 /* we hit this either if it's the very first time we run this, or
212 * when /proc/diskstats overflows; while 0 is not correct, it's at
213 * least not way off */
217 last_read = current_read;
218 last_write = current_write;
220 info.diskio_value = tot;
221 info.diskio_read_value = tot_read;
222 info.diskio_write_value = tot_write;