1/*
2 *  Unix SMB/CIFS implementation.
3 *  Performance Counter Daemon
4 *
5 *  Copyright (C) Marcin Krzysztof Porwit    2005
6 *
7 *  This program is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 *
12 *  This program is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "perf.h"
23
24void init_diskdata_desc(PERF_DATA_BLOCK *data)
25{
26	init_perf_counter(&(data->diskInfo.diskObjDesc),
27			  &(data->diskInfo.diskObjDesc),
28			  get_counter_id(data),
29			  "Logical Disk",
30			  "The Logical Disk object consists of counters that show information about disks.",
31			  0,
32			  PERF_OBJECT);
33	init_perf_counter(&(data->diskInfo.freeMegs),
34			  &(data->diskInfo.diskObjDesc),
35			  get_counter_id(data),
36			  "Megabytes Free",
37			  "The amount of available disk space, in megabytes.",
38			  PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
39			  PERF_COUNTER);
40	init_perf_counter(&(data->diskInfo.writesPerSec),
41			  &(data->diskInfo.diskObjDesc),
42			  get_counter_id(data),
43			  "Writes/sec",
44			  "The number of writes per second to that disk.",
45			  PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
46			  PERF_COUNTER);
47	init_perf_counter(&(data->diskInfo.readsPerSec),
48			  &(data->diskInfo.diskObjDesc),
49			  get_counter_id(data),
50			  "Reads/sec",
51			  "The number of reads of that disk per second.",
52			  PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
53			  PERF_COUNTER);
54
55	return;
56}
57void init_num_disks(PERF_DATA_BLOCK *data)
58{
59	FILE *mtab;
60	char buf[PROC_BUF];
61	char *start, *stop;
62	int i = 0, num;
63
64	if(!(mtab = fopen("/etc/mtab", "r")))
65	{
66		perror("init_disk_names: fopen");
67		exit(1);
68	}
69
70	rewind(mtab);
71	fflush(mtab);
72
73	while(fgets(buf, sizeof(buf), mtab))
74	{
75		if(start = strstr(buf, "/dev/"))
76		{
77			if(start = strstr(start, "da"))
78			{
79				i++;
80			}
81		}
82	}
83
84	data->diskInfo.numDisks = i;
85	fclose(mtab);
86
87	return;
88}
89
90void init_disk_names(PERF_DATA_BLOCK *data)
91{
92	FILE *mtab;
93	char buf[PROC_BUF];
94	char *start, *stop;
95	int i = 0, num;
96
97	if(!(mtab = fopen("/etc/mtab", "r")))
98	{
99		perror("init_disk_names: fopen");
100		exit(1);
101	}
102
103	rewind(mtab);
104	fflush(mtab);
105
106	while(fgets(buf, sizeof(buf), mtab))
107	{
108		if(start = strstr(buf, "/dev/"))
109		{
110			if(start = strstr(start, "da"))
111			{
112				start -=1;
113				stop = strstr(start, " ");
114				memcpy(data->diskInfo.mdata[i].name, start, stop - start);
115				start = stop +1;
116				stop = strstr(start, " ");
117				memcpy(data->diskInfo.mdata[i].mountpoint, start, stop - start);
118				i++;
119			}
120		}
121	}
122
123	fclose(mtab);
124
125	return;
126}
127
128void get_diskinfo(PERF_DATA_BLOCK *data)
129{
130	int i;
131	DiskData *p;
132	struct statfs statfsbuf;
133	int status, num;
134	char buf[LARGE_BUF], *start;
135	FILE *diskstats;
136	long reads, writes, discard;
137
138	diskstats = fopen("/proc/diskstats", "r");
139	rewind(diskstats);
140	fflush(diskstats);
141	status = fread(buf, sizeof(char), LARGE_BUF, diskstats);
142	fclose(diskstats);
143
144	for(i = 0; i < data->diskInfo.numDisks; i++)
145	{
146		p = &(data->diskInfo.data[i]);
147		status = statfs(data->diskInfo.mdata[i].mountpoint, &statfsbuf);
148		p->freeMegs = (statfsbuf.f_bfree*statfsbuf.f_bsize)/1048576;
149		start = strstr(buf, data->diskInfo.mdata[i].name);
150		start += strlen(data->diskInfo.mdata[i].name) + 1;
151		num = sscanf(start, "%u %u %u %u",
152			     &reads,
153			     &discard,
154			     &writes,
155			     &discard);
156		p->writesPerSec = writes;
157		p->readsPerSec = reads;
158		fprintf(stderr, "%s:\t%u\t%u\n",
159			data->diskInfo.mdata[i].mountpoint,
160			reads, writes);
161	}
162	return;
163}
164void init_disk_data(PERF_DATA_BLOCK *data)
165{
166	init_diskdata_desc(data);
167
168	init_num_disks(data);
169
170	data->diskInfo.mdata = calloc(data->diskInfo.numDisks, sizeof(DiskMetaData));
171	if(!data->diskInfo.mdata)
172	{
173		fatal("init_disk_data: out of memory");
174	}
175
176	init_disk_names(data);
177
178	data->diskInfo.data = calloc(data->diskInfo.numDisks, sizeof(DiskData));
179	if(!data->diskInfo.data)
180	{
181		fatal("init_disk_data: out of memory");
182	}
183
184	get_diskinfo(data);
185
186	return;
187}
188
189void output_disk_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
190{
191	output_perf_desc(data->diskInfo.diskObjDesc, rt);
192	output_perf_desc(data->diskInfo.freeMegs, rt);
193	output_perf_desc(data->diskInfo.writesPerSec, rt);
194	output_perf_desc(data->diskInfo.readsPerSec, rt);
195	output_num_instances(data->diskInfo.diskObjDesc, data->diskInfo.numDisks, rt);
196
197	return;
198}
199
200void output_diskinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
201{
202	int i;
203
204	output_perf_counter(data->diskInfo.freeMegs,
205			    data->diskInfo.data[0].freeMegs,
206			    rt, tdb_flags);
207	output_perf_counter(data->diskInfo.writesPerSec,
208			    (unsigned long long)data->diskInfo.data[0].writesPerSec,
209			    rt, tdb_flags);
210	output_perf_counter(data->diskInfo.readsPerSec,
211			    (unsigned long long)data->diskInfo.data[0].readsPerSec,
212			    rt, tdb_flags);
213
214	for(i = 0; i < data->diskInfo.numDisks; i++)
215	{
216		output_perf_instance(data->diskInfo.diskObjDesc.index,
217				     i,
218				     (void *)&(data->diskInfo.data[i]),
219				     sizeof(DiskData),
220				     data->diskInfo.mdata[i].mountpoint,
221				     rt, tdb_flags);
222	}
223
224	return;
225}
226