1 | /* |
2 | KSysGuard, the KDE System Guard |
3 | |
4 | Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> |
5 | |
6 | This program is free software; you can redistribute it and/or |
7 | modify it under the terms of version 2 of the GNU General Public |
8 | License as published by the Free Software Foundation. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | |
19 | */ |
20 | |
21 | #include <config-workspace.h> |
22 | |
23 | #include <mntent.h> |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | #include <sys/statvfs.h> |
28 | #include <time.h> |
29 | #include <unistd.h> |
30 | #include <ctype.h> |
31 | |
32 | #include "Command.h" |
33 | #include "ccont.h" |
34 | #include "diskstat.h" |
35 | #include "ksysguardd.h" |
36 | |
37 | typedef struct { |
38 | char device[ 256 ]; |
39 | char mntpnt[ 256 ]; |
40 | struct statvfs statvfs; |
41 | } DiskInfo; |
42 | |
43 | static CONTAINER DiskStatList = 0; |
44 | static CONTAINER OldDiskStatList = 0; |
45 | static struct SensorModul* DiskStatSM; |
46 | char *getMntPnt( const char* cmd ); |
47 | |
48 | static void sanitize(char *str) { |
49 | if(str == NULL) |
50 | return; |
51 | while (*str != 0) { |
52 | if(*str == '\t' || *str == '\n' || *str == '\r' || *str == ' ' || !isascii(*str) ) |
53 | *str = '?'; |
54 | ++str; |
55 | } |
56 | } |
57 | |
58 | char *getMntPnt( const char* cmd ) |
59 | { |
60 | static char device[ 1025 ]; |
61 | char* ptr; |
62 | |
63 | memset( device, 0, sizeof( device ) ); |
64 | sscanf( cmd, "partitions%1024s" , device ); |
65 | |
66 | ptr = (char*)rindex( device, '/' ); |
67 | *ptr = '\0'; |
68 | |
69 | return (char*)device; |
70 | } |
71 | |
72 | /* ----------------------------- public part ------------------------------- */ |
73 | |
74 | static char monitor[ 1024 ]; |
75 | static void registerMonitors(const char* mntpnt) { |
76 | snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace" , mntpnt ); |
77 | registerMonitor( monitor, "integer" , printDiskStatUsed, printDiskStatUsedInfo, DiskStatSM ); |
78 | snprintf( monitor, sizeof( monitor ), "partitions%s/freespace" , mntpnt ); |
79 | registerMonitor( monitor, "integer" , printDiskStatFree, printDiskStatFreeInfo, DiskStatSM ); |
80 | snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel" , mntpnt ); |
81 | registerMonitor( monitor, "integer" , printDiskStatPercent, printDiskStatPercentInfo, DiskStatSM ); |
82 | } |
83 | static void removeMonitors(const char* mntpnt) { |
84 | snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace" , mntpnt ); |
85 | removeMonitor( monitor ); |
86 | snprintf( monitor, sizeof( monitor ), "partitions%s/freespace" , mntpnt ); |
87 | removeMonitor( monitor ); |
88 | snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel" , mntpnt ); |
89 | removeMonitor( monitor ); |
90 | } |
91 | |
92 | void initDiskStat( struct SensorModul* sm ) |
93 | { |
94 | DiskInfo* disk_info; |
95 | |
96 | DiskStatList = NULL; |
97 | OldDiskStatList = NULL; |
98 | DiskStatSM = sm; |
99 | if ( updateDiskStat() < 0 ) |
100 | return; |
101 | |
102 | registerMonitor( "partitions/list" , "listview" , printDiskStat, printDiskStatInfo, sm ); |
103 | |
104 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
105 | registerMonitors(disk_info->mntpnt); |
106 | } |
107 | } |
108 | |
109 | void exitDiskStat( void ) |
110 | { |
111 | DiskInfo* disk_info; |
112 | |
113 | removeMonitor( "partitions/list" ); |
114 | |
115 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
116 | removeMonitors(disk_info->mntpnt); |
117 | } |
118 | |
119 | destr_ctnr( DiskStatList, free ); |
120 | if(OldDiskStatList) |
121 | destr_ctnr( OldDiskStatList, free ); |
122 | } |
123 | |
124 | void checkDiskStat( void ) |
125 | { |
126 | updateDiskStat(); |
127 | DiskInfo* disk_info_new; |
128 | DiskInfo* disk_info_old; |
129 | int changed = 0; |
130 | for ( disk_info_new = first_ctnr( DiskStatList ); disk_info_new; disk_info_new = next_ctnr( DiskStatList ) ) { |
131 | int found = 0; |
132 | for ( disk_info_old = first_ctnr( OldDiskStatList ); disk_info_old; disk_info_old = next_ctnr( OldDiskStatList ) ) { |
133 | if(strcmp(disk_info_new->mntpnt, disk_info_old->mntpnt) == 0) { |
134 | free( remove_ctnr( OldDiskStatList ) ); |
135 | found = 1; |
136 | continue; |
137 | } |
138 | } |
139 | if(!found) { |
140 | /* register all the devices that did not exist before*/ |
141 | registerMonitors(disk_info_new->mntpnt); |
142 | changed++; |
143 | } |
144 | } |
145 | /*Now remove all the devices that do not exist anymore*/ |
146 | for ( disk_info_old = first_ctnr( OldDiskStatList ); disk_info_old; disk_info_old = next_ctnr( OldDiskStatList ) ) { |
147 | removeMonitors(disk_info_old->mntpnt); |
148 | changed++; |
149 | } |
150 | destr_ctnr( OldDiskStatList, free ); |
151 | OldDiskStatList = NULL; |
152 | updateDiskStat(); |
153 | if(changed) |
154 | print_error( "RECONFIGURE" ); /*Let ksysguard know that we've added a sensor*/ |
155 | } |
156 | |
157 | int updateDiskStat( void ) |
158 | { |
159 | DiskInfo *disk_info; |
160 | FILE *fh; |
161 | struct mntent *mnt_info; |
162 | |
163 | if ( ( fh = setmntent( "/etc/mtab" , "r" ) ) == NULL ) { |
164 | print_error( "Cannot open \'/etc/mtab\'!\n" ); |
165 | return -1; |
166 | } |
167 | if(OldDiskStatList == 0) { |
168 | OldDiskStatList = DiskStatList; |
169 | DiskStatList = new_ctnr(); |
170 | } else { |
171 | empty_ctnr(DiskStatList); |
172 | } |
173 | |
174 | while ( ( mnt_info = getmntent( fh ) ) != NULL ) { |
175 | /* |
176 | * An entry which device name doesn't start with a '/' is |
177 | * either a dummy file system or a network file system. |
178 | * Add special handling for smbfs and cifs as is done by |
179 | * coreutils as well. |
180 | */ |
181 | if ( (mnt_info->mnt_fsname[0] != '/') || |
182 | !strcmp( mnt_info->mnt_type, "smbfs" ) || |
183 | !strcmp( mnt_info->mnt_type, "cifs" ) || |
184 | !strcmp( mnt_info->mnt_type, "proc" ) || |
185 | !strcmp( mnt_info->mnt_type, "devfs" ) || |
186 | !strcmp( mnt_info->mnt_type, "usbfs" ) || |
187 | !strcmp( mnt_info->mnt_type, "sysfs" ) || |
188 | !strcmp( mnt_info->mnt_type, "tmpfs" ) || |
189 | !strcmp( mnt_info->mnt_type, "devpts" ) ) |
190 | continue; /* Skip these file systems */ |
191 | |
192 | if ( ( disk_info = (DiskInfo *)malloc( sizeof( DiskInfo ) ) ) == NULL ) |
193 | continue; |
194 | |
195 | memset( disk_info, 0, sizeof( DiskInfo ) ); |
196 | |
197 | if ( statvfs( mnt_info->mnt_dir, &(disk_info->statvfs) ) < 0 ) |
198 | continue; |
199 | |
200 | strncpy( disk_info->device, mnt_info->mnt_fsname, sizeof( disk_info->device ) ); |
201 | disk_info->device[ sizeof(disk_info->device) -1] = 0; |
202 | |
203 | strncpy( disk_info->mntpnt, mnt_info->mnt_dir, sizeof( disk_info->mntpnt ) ); |
204 | disk_info->mntpnt[ sizeof(disk_info->mntpnt) - 1] = 0; |
205 | sanitize(disk_info->mntpnt); |
206 | |
207 | push_ctnr( DiskStatList, disk_info ); |
208 | } |
209 | endmntent( fh ); |
210 | |
211 | return 0; |
212 | } |
213 | |
214 | int calculatePercentageUsed( unsigned long totalSizeKB, unsigned long available) { |
215 | if (!available) |
216 | return 0; |
217 | |
218 | unsigned long totalSizeKBdividedBy100 = (50 + totalSizeKB )/ 100; |
219 | if (!totalSizeKBdividedBy100) |
220 | return 0; |
221 | |
222 | int percentageUsed = 100 - available / totalSizeKBdividedBy100; /* Percentage is 1 - available / totalSizeKB, meaning that we count root-only reserved space as "used" here */ |
223 | /* If we have rounded down to 0%, make it 1%, like "df" does */ |
224 | if (percentageUsed == 0) |
225 | return 1; |
226 | return percentageUsed; |
227 | } |
228 | |
229 | void printDiskStat( const char* cmd ) |
230 | { |
231 | DiskInfo* disk_info; |
232 | |
233 | (void)cmd; |
234 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
235 | /* See man statvfs(2) for meaning of fields */ |
236 | unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); |
237 | unsigned long usedKB = totalSizeKB - (disk_info->statvfs.f_bfree * (disk_info->statvfs.f_bsize/1024)); /* used is the total size minus free blocks including those for root only */ |
238 | unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ |
239 | int percentageUsed = calculatePercentageUsed(totalSizeKB, available); |
240 | output( "%s\t%ld\t%ld\t%ld\t%d\t%s\n" , |
241 | disk_info->device, |
242 | totalSizeKB, |
243 | usedKB, |
244 | available, |
245 | percentageUsed, |
246 | disk_info->mntpnt ); |
247 | } |
248 | |
249 | output( "\n" ); |
250 | } |
251 | |
252 | void printDiskStatInfo( const char* cmd ) |
253 | { |
254 | (void)cmd; |
255 | output( "Device\tSize\tUsed\tAvailable\tUsed %%\tMount point\nM\tKB\tKB\tKB\t%%\ts\n" ); |
256 | } |
257 | |
258 | void printDiskStatUsed( const char* cmd ) |
259 | { |
260 | char *mntpnt = (char*)getMntPnt( cmd ); |
261 | DiskInfo* disk_info; |
262 | |
263 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
264 | if ( !strcmp( mntpnt, disk_info->mntpnt ) ) { |
265 | unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); |
266 | unsigned long usedKB = totalSizeKB - (disk_info->statvfs.f_bfree * (disk_info->statvfs.f_bsize/1024)); /* used is the total size minus free blocks including those for root only */ |
267 | output( "%ld\n" , usedKB ); |
268 | } |
269 | } |
270 | |
271 | output( "\n" ); |
272 | } |
273 | |
274 | void printDiskStatUsedInfo( const char* cmd ) |
275 | { |
276 | (void)cmd; |
277 | output( "Used\t0\t0\tKB\n" ); |
278 | } |
279 | |
280 | void printDiskStatFree( const char* cmd ) |
281 | { |
282 | char *mntpnt = (char*)getMntPnt( cmd ); |
283 | DiskInfo* disk_info; |
284 | |
285 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
286 | if ( !strcmp( mntpnt, disk_info->mntpnt ) ) { |
287 | unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ |
288 | output( "%ld\n" , available ); |
289 | } |
290 | } |
291 | output( "\n" ); |
292 | } |
293 | |
294 | void printDiskStatFreeInfo( const char* cmd ) |
295 | { |
296 | (void)cmd; |
297 | output( "Available\t0\t0\tKB\n" ); |
298 | } |
299 | |
300 | void printDiskStatPercent( const char* cmd ) |
301 | { |
302 | char *mntpnt = (char*)getMntPnt( cmd ); |
303 | DiskInfo* disk_info; |
304 | |
305 | for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { |
306 | if ( !strcmp( mntpnt, disk_info->mntpnt ) ) { |
307 | unsigned long totalSizeKB = disk_info->statvfs.f_blocks * (disk_info->statvfs.f_frsize/1024); |
308 | unsigned long available = disk_info->statvfs.f_bavail * (disk_info->statvfs.f_bsize/1024); /* available is only those for non-root. So available + used != total because some are reserved for root */ |
309 | |
310 | int percentageUsed = calculatePercentageUsed(totalSizeKB, available); |
311 | output( "%d\n" , percentageUsed ); |
312 | } |
313 | } |
314 | |
315 | output( "\n" ); |
316 | } |
317 | |
318 | void printDiskStatPercentInfo( const char* cmd ) |
319 | { |
320 | (void)cmd; |
321 | output( "Percentage Used\t0\t100\t%%\n" ); |
322 | } |
323 | |