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/>.
30 #include "conky.h" /* text_buffer_size */
36 /* The following ifdefs were adapted from gkrellm */
37 #include <linux/major.h>
39 #if !defined(MD_MAJOR)
43 #if !defined(LVM_BLK_MAJOR)
44 #define LVM_BLK_MAJOR 58
47 #if !defined(NBD_MAJOR)
51 static struct diskio_stat diskio_stats_[MAX_DISKIO_STATS];
52 struct diskio_stat *diskio_stats = diskio_stats_;
54 void clear_diskio_stats(void)
57 for(i = 0; i < MAX_DISKIO_STATS; i++) {
58 if (diskio_stats[i].dev) {
59 free(diskio_stats[i].dev);
60 diskio_stats[i].dev = 0;
65 struct diskio_stat *prepare_diskio_stat(const char *s)
67 struct diskio_stat *new = 0;
71 char device[text_buffer_size], fbuf[text_buffer_size];
73 /* lookup existing or get new */
74 for (i = 0; i < MAX_DISKIO_STATS; i++) {
75 if (diskio_stats[i].dev) {
76 if (strcmp(diskio_stats[i].dev, s) == 0) {
77 return &diskio_stats[i];
80 new = &diskio_stats[i];
86 ERR("too many diskio stats");
93 new->dev = strndup(s, text_buffer_size);
96 * check that device actually exists
99 if (!(fp = open_file("/proc/diskstats", &rep))) {
100 ERR("cannot read from /proc/diskstats");
105 fgets(fbuf, text_buffer_size, fp);
106 if (sscanf(fbuf, "%*u %*u %255s %*u %*u %*u %*u %*u %*u %*u", device)) {
107 // check for device match
108 if (strncmp(new->dev, device, 256) == 0) {
117 ERR("diskio device '%s' does not exist", s);
121 new->current_read = 0;
122 new ->current_write = 0;
123 new->last = UINT_MAX;
124 new->last_read = UINT_MAX;
125 new->last_write = UINT_MAX;
129 void update_diskio(void)
131 static unsigned int last = UINT_MAX;
132 static unsigned int last_read = UINT_MAX;
133 static unsigned int last_write = UINT_MAX;
137 char buf[512], devbuf[64];
139 unsigned int major, minor;
140 unsigned int current = 0;
141 unsigned int current_read = 0;
142 unsigned int current_write = 0;
143 unsigned int reads, writes = 0;
145 int tot, tot_read, tot_write;
147 if (!(fp = open_file("/proc/diskstats", &rep))) {
148 info.diskio_value = 0;
152 /* read reads and writes from all disks (minor = 0), including cd-roms
153 * and floppies, and sum them up */
156 col_count = sscanf(buf, "%u %u %s %*u %*u %u %*u %*u %*u %u", &major,
157 &minor, devbuf, &reads, &writes);
158 /* ignore subdevices (they have only 3 matching entries in their line)
159 * and virtual devices (LVM, network block devices, RAM disks, Loopback)
161 * XXX: ignore devices which are part of a SW RAID (MD_MAJOR) */
162 if (col_count == 5 && major != LVM_BLK_MAJOR && major != NBD_MAJOR
163 && major != RAMDISK_MAJOR && major != LOOP_MAJOR) {
164 current += reads + writes;
165 current_read += reads;
166 current_write += writes;
168 col_count = sscanf(buf, "%u %u %s %*u %u %*u %u",
169 &major, &minor, devbuf, &reads, &writes);
170 if (col_count != 5) {
174 for (i = 0; i < MAX_DISKIO_STATS; i++) {
175 if (diskio_stats[i].dev &&
176 strncmp(devbuf, diskio_stats[i].dev, text_buffer_size) == 0) {
177 diskio_stats[i].current =
178 (reads + writes - diskio_stats[i].last) / 2;
179 diskio_stats[i].current_read =
180 (reads - diskio_stats[i].last_read) / 2;
181 diskio_stats[i].current_write =
182 (writes - diskio_stats[i].last_write) / 2;
183 if (reads + writes < diskio_stats[i].last) {
184 diskio_stats[i].current = 0;
186 if (reads < diskio_stats[i].last_read) {
187 diskio_stats[i].current_read = 0;
188 diskio_stats[i].current = diskio_stats[i].current_write;
190 if (writes < diskio_stats[i].last_write) {
191 diskio_stats[i].current_write = 0;
192 diskio_stats[i].current = diskio_stats[i].current_read;
194 diskio_stats[i].last = reads + writes;
195 diskio_stats[i].last_read = reads;
196 diskio_stats[i].last_write = writes;
201 /* since the values in /proc/diststats are absolute, we have to substract
202 * our last reading. The numbers stand for "sectors read", and we therefore
203 * have to divide by two to get KB */
204 tot = ((double) (current - last) / 2);
205 tot_read = ((double) (current_read - last_read) / 2);
206 tot_write = ((double) (current_write - last_write) / 2);
208 if (last_read > current_read) {
211 if (last_write > current_write) {
215 if (last > current) {
216 /* we hit this either if it's the very first time we run this, or
217 * when /proc/diskstats overflows; while 0 is not correct, it's at
218 * least not way off */
222 last_read = current_read;
223 last_write = current_write;
225 info.diskio_value = tot;
226 info.diskio_read_value = tot_read;
227 info.diskio_write_value = tot_write;