1 | /* |
2 | KSysGuard, the KDE System Guard |
3 | |
4 | Copyright (c) 2007 Greg Martyn <greg.martyn@gmail.com>, John Tapsell <tapsell@kde.org> |
5 | |
6 | This program is free software; you can redistribute it and/or |
7 | modify it under the terms of version 2 or later 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 | #include "Command.h" |
21 | #include "ksysguardd.h" |
22 | #include "softraid.h" |
23 | |
24 | #include <string.h> /* for strlen, strcat and strcmp */ |
25 | #include <stdio.h> /* for sprintf */ |
26 | #include <sys/types.h> /* for open */ |
27 | #include <sys/stat.h> /* for open */ |
28 | #include <fcntl.h> /* for open */ |
29 | #include <unistd.h> /* for read, close, exec, fork */ |
30 | #include <stdlib.h> /* for exit */ |
31 | #include <sys/wait.h> /* for wait :) */ |
32 | #include <stdbool.h> /* for bool */ |
33 | #include "ccont.h" /* for CONTAINER */ |
34 | |
35 | #define MDSTATBUFSIZE (1 * 1024) |
36 | #define MDADMSTATBUFSIZE (2 * 1024) |
37 | #define ARRAYNAMELEN 32 |
38 | #define ARRAYNAMELENSTRING "32" |
39 | |
40 | static struct SensorModul* StatSM; |
41 | |
42 | static CONTAINER ArrayInfos = 0; |
43 | char mdstatBuf[ MDSTATBUFSIZE ]; /* Buffer for /proc/mdstat */ |
44 | |
45 | typedef struct Disks { |
46 | char *name; /* e.g. hda1 */ |
47 | char status; /* e.g. F for failed, S for spare. U for fully synced, _ for syncing */ |
48 | int index; /* number in the array */ |
49 | struct Disks *next; /* A pointer to the next disk in this array. NULL if no next */ |
50 | } Disks; |
51 | |
52 | typedef struct { |
53 | bool Alive; |
54 | |
55 | |
56 | /* from /sbin/mdadm --detail /dev/ArrayName */ |
57 | bool ArraySizeIsAlive; |
58 | bool ArraySizeIsRegistered; |
59 | int ArraySizeKB; |
60 | |
61 | bool UsedDeviceSizeIsAlive; |
62 | bool UsedDeviceSizeIsRegistered; |
63 | int UsedDeviceSizeKB; |
64 | |
65 | bool PreferredMinorIsAlive; |
66 | bool PreferredMinorIsRegistered; |
67 | int PreferredMinor; |
68 | |
69 | /* from /proc/mdstat */ |
70 | char ArrayName[ ARRAYNAMELEN +1]; |
71 | int NumBlocks; |
72 | |
73 | int NumRaidDevices; /* Number of 'useful' disks. Included working and spare disks, but not failed. */ |
74 | |
75 | int TotalDevices; /* Total number of devices, including failed and spare disks */ |
76 | |
77 | int ActiveDevices; /* Active means it's fully synced, and working, so not a spare or failed */ |
78 | |
79 | int WorkingDevices; /* Working means it's in the raid (not a spare or failed) but it may or may not be fully synced. Active - Working = number being synced */ |
80 | |
81 | int FailedDevices; /* Number of failed devices */ |
82 | |
83 | int SpareDevices; /* Number of spare devices, WE DO NOT Include Failed devices here, unlike mdadm. */ |
84 | |
85 | int devnum; /* Raid array number. e.g. if ArrayName is "md0", then devnum=0 */ |
86 | bool ArrayActive; /* Whether this raid is active */ |
87 | char *level; /* Raid1, Raid2, etc */ |
88 | char *pattern; /* U for up, _ for down */ |
89 | int ResyncingPercent; /* -1 if not resyncing, otherwise between 0 to 100 */ |
90 | bool IsCurrentlyReSyncing; /* True if currently resyncing - */ |
91 | Disks *first_disk; /* A linked list of hard disks */ |
92 | } ArrayInfo; |
93 | |
94 | static int ArrayInfoEqual( void* s1, void* s2 ) |
95 | { |
96 | /* Returns 0 if both ArrayInfos have the same name. */ |
97 | return strncmp( ((ArrayInfo*)s1)->ArrayName, ((ArrayInfo*)s2)->ArrayName,ARRAYNAMELEN ); |
98 | } |
99 | |
100 | void printArrayAttribute( const char* cmd ) { |
101 | INDEX idx; |
102 | ArrayInfo key; |
103 | ArrayInfo* foundArray; |
104 | char attribute[40]; |
105 | |
106 | if ( sscanf(cmd, "SoftRaid/%[^/]/%39s" , key.ArrayName, attribute) == 2 ) { |
107 | if ( ( idx = search_ctnr( ArrayInfos, ArrayInfoEqual, &key ) ) == 0 ) { |
108 | foundArray = get_ctnr( ArrayInfos, idx ); |
109 | |
110 | if ( strcmp( attribute, "NumBlocks" ) == 0 ) |
111 | output( "%d\n" , foundArray->NumBlocks ); |
112 | else if ( strcmp( attribute, "ArraySizeKB" ) == 0 ) |
113 | output( "%d\n" , foundArray->ArraySizeKB ); |
114 | else if ( strcmp( attribute, "UsedDeviceSizeKB" ) == 0 ) |
115 | output( "%d\n" , foundArray->UsedDeviceSizeKB ); |
116 | else if ( strcmp( attribute, "NumRaidDevices" ) == 0 ) |
117 | output( "%d\n" , foundArray->NumRaidDevices ); |
118 | else if ( strcmp( attribute, "TotalDevices" ) == 0 ) |
119 | output( "%d\n" , foundArray->TotalDevices ); |
120 | else if ( strcmp( attribute, "PreferredMinor" ) == 0 ) |
121 | output( "%d\n" , foundArray->PreferredMinor ); |
122 | else if ( strcmp( attribute, "ActiveDevices" ) == 0 ) |
123 | output( "%d\n" , foundArray->ActiveDevices ); |
124 | else if ( strcmp( attribute, "WorkingDevices" ) == 0 ) |
125 | output( "%d\n" , foundArray->WorkingDevices ); |
126 | else if ( strcmp( attribute, "FailedDevices" ) == 0 ) |
127 | output( "%d\n" , foundArray->FailedDevices ); |
128 | else if ( strcmp( attribute, "SpareDevices" ) == 0 ) |
129 | output( "%d\n" , foundArray->SpareDevices ); |
130 | else if( strcmp( attribute, "DeviceNumber" ) == 0 ) |
131 | output( "%d\n" , foundArray->devnum); |
132 | else if( strcmp( attribute, "ResyncingPercent" ) == 0 ) |
133 | output( "%d\n" , foundArray->ResyncingPercent); |
134 | else if( strcmp( attribute, "RaidType" ) == 0 ) |
135 | output( "%s\n" , foundArray->level); |
136 | else if( strcmp( attribute, "DiskInfo" ) == 0 ) { |
137 | Disks *disk = foundArray->first_disk; |
138 | while(disk) { |
139 | output( "%s\t%d\t%c\n" , disk->name, disk->index, disk->status); |
140 | disk = disk->next; |
141 | } |
142 | output( "\n" ); |
143 | } |
144 | } |
145 | else { |
146 | output( "\n" ); |
147 | } |
148 | } else { |
149 | output( "\n" ); |
150 | } |
151 | |
152 | |
153 | } |
154 | |
155 | void printArrayAttributeInfo( const char* cmd ) { |
156 | INDEX idx; |
157 | ArrayInfo key; |
158 | ArrayInfo* foundArray; |
159 | char attribute[40]; |
160 | |
161 | if ( sscanf(cmd, "SoftRaid/%[^/]/%39s" , key.ArrayName, attribute) == 2 ) { |
162 | if ( ( idx = search_ctnr( ArrayInfos, ArrayInfoEqual, &key ) ) == 0 ) { |
163 | foundArray = get_ctnr( ArrayInfos, idx ); |
164 | |
165 | if ( strcmp( attribute, "NumBlocks?" ) == 0 ) |
166 | output( "Num blocks\t0\t0\t\n" ); |
167 | else if ( strcmp( attribute, "ArraySizeKB?" ) == 0 ) |
168 | output( "Array size\t0\t0\tKB\n" ); |
169 | else if ( strcmp( attribute, "UsedDeviceSizeKB?" ) == 0 ) |
170 | output( "Used Device Size\t0\t0\tKB\n" ); |
171 | else if ( strcmp( attribute, "NumRaidDevices?" ) == 0 ) |
172 | output( "Total number of raid devices\t0\t0\t\n" ); |
173 | else if ( strcmp( attribute, "TotalDevices?" ) == 0 ) |
174 | output( "Total number of devices\t0\t0\t\n" ); |
175 | else if ( strcmp( attribute, "PreferredMinor?" ) == 0 ) |
176 | output( "The preferred minor\t0\t0\t\n" ); |
177 | else if ( strcmp( attribute, "ActiveDevices?" ) == 0 ) |
178 | output( "Number of active devices\t0\t%d\t\n" , foundArray->TotalDevices ); |
179 | else if ( strcmp( attribute, "WorkingDevices?" ) == 0 ) |
180 | output( "Number of working devices\t0\t%d\t\n" , foundArray->TotalDevices ); |
181 | else if ( strcmp( attribute, "FailedDevices?" ) == 0 ) |
182 | output( "Number of failed devices\t0\t%d\t\n" , foundArray->TotalDevices ); |
183 | else if ( strcmp( attribute, "SpareDevices?" ) == 0 ) |
184 | output( "Number of spare devices\t0\t%d\t\n" , foundArray->TotalDevices ); |
185 | else if( strcmp( attribute, "DeviceNumber?" ) == 0 ) |
186 | output( "Raid Device Number\t0\t0\t\n" ); |
187 | else if( strcmp( attribute, "ResyncingPercent?" ) == 0 ) |
188 | output( "Resyncing Percentage Done. -1 if not resyncing\t-1\t100\t%%\n" ); |
189 | else if( strcmp( attribute, "RaidType?" ) == 0 ) |
190 | output( "Type of RAID array\n" ); |
191 | else if( strcmp( attribute, "DiskInfo?" ) == 0 ) |
192 | output( "Disk Name\tIndex\tStatus\ns\td\tS\n" ); |
193 | } |
194 | else { |
195 | output( "\n" ); |
196 | } |
197 | } else { |
198 | output( "\n" ); |
199 | } |
200 | } |
201 | |
202 | |
203 | |
204 | void getMdadmDetail( ArrayInfo* MyArray ) { |
205 | int fd[2]; |
206 | pid_t ChildPID; |
207 | ssize_t nbytes; |
208 | |
209 | char sensorName[128]; |
210 | char arrayDevice[ARRAYNAMELEN + 5]; |
211 | char format[ 32 ]; |
212 | char lineBuf[ 1024 ]; |
213 | char mdadmStatBuf[ MDADMSTATBUFSIZE ]; /* Buffer for mdadm --detail */ |
214 | char* mdadmStatBufP; |
215 | |
216 | /* Create a pipe */ |
217 | if(pipe(fd) == -1) |
218 | { |
219 | perror("Could not create a pipe to launch mdadm." ); |
220 | exit(1); |
221 | } |
222 | |
223 | /* Fork */ |
224 | if((ChildPID = fork()) == -1) |
225 | { |
226 | perror("Could not fork to launch mdadm." ); |
227 | exit(1); |
228 | } |
229 | |
230 | /* Child will execute the program, parent will listen. */ |
231 | |
232 | if (ChildPID == 0) { |
233 | /* Child process */ |
234 | |
235 | /* Child will execute the program, parent will listen. */ |
236 | /* Close stdout, duplicate the input side of pipe to stdout */ |
237 | dup2(fd[1], 1); |
238 | /* Close output side of pipe */ |
239 | close(fd[0]); |
240 | close(2); |
241 | |
242 | snprintf( arrayDevice, sizeof( arrayDevice ), "/dev/%s" , MyArray->ArrayName ); |
243 | execl ("/sbin/mdadm" , "mdadm" , "--detail" , arrayDevice, (char *)0); |
244 | exit(0); /* In case /sbin/mdadm isn't found */ |
245 | /* Child is now dead, as per our request */ |
246 | } |
247 | |
248 | /* Parent process */ |
249 | |
250 | /* Close input side of pipe */ |
251 | close(fd[1]); |
252 | |
253 | waitpid( ChildPID, 0, 0); |
254 | |
255 | /* Fill mdadmStatBuf with pipe's output */ |
256 | nbytes = read( fd[0], mdadmStatBuf, MDADMSTATBUFSIZE-1 ); |
257 | if (nbytes >= 0) |
258 | mdadmStatBuf[nbytes] = '\0'; |
259 | |
260 | /* Now, go through mdadmStatBuf line by line. Register monitors along the way */ |
261 | sprintf( format, "%%%d[^\n]\n" , (int)sizeof( lineBuf ) - 1 ); |
262 | mdadmStatBufP = mdadmStatBuf; |
263 | while (sscanf(mdadmStatBufP, format, lineBuf) != EOF) { |
264 | lineBuf[sizeof(lineBuf) - 1] = '\0'; |
265 | mdadmStatBufP += strlen(lineBuf) + 1; /* move mdadmStatBufP to next line */ |
266 | |
267 | if ( sscanf(lineBuf, " Array Size : %d" , &MyArray->ArraySizeKB) == 1 ) { |
268 | MyArray->ArraySizeIsAlive = true; |
269 | if ( !MyArray->ArraySizeIsRegistered ) { |
270 | sprintf(sensorName, "SoftRaid/%s/ArraySizeKB" , MyArray->ArrayName); |
271 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
272 | |
273 | MyArray->ArraySizeIsRegistered = true; |
274 | } |
275 | } |
276 | |
277 | /* Versions of mdadm prior to 2.6 used "Device Size" instead of "Used Dev Size" |
278 | */ |
279 | else if ( ( sscanf(lineBuf, " Device Size : %d" , &MyArray->UsedDeviceSizeKB) == 1 ) || |
280 | ( sscanf(lineBuf, " Used Dev Size : %d" , &MyArray->UsedDeviceSizeKB) == 1 ) ) { |
281 | MyArray->UsedDeviceSizeIsAlive = true; |
282 | if ( !MyArray->UsedDeviceSizeIsRegistered ) { |
283 | sprintf(sensorName, "SoftRaid/%s/UsedDeviceSizeKB" , MyArray->ArrayName); |
284 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
285 | MyArray->UsedDeviceSizeIsRegistered = true; |
286 | } |
287 | } |
288 | |
289 | else if ( sscanf(lineBuf, "Preferred Minor : %d" , &MyArray->PreferredMinor) == 1 ) { |
290 | MyArray->PreferredMinorIsAlive = true; |
291 | if ( !MyArray->PreferredMinorIsRegistered ) { |
292 | sprintf(sensorName, "SoftRaid/%s/PreferredMinor" , MyArray->ArrayName); |
293 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
294 | MyArray->PreferredMinorIsRegistered = true; |
295 | } |
296 | } |
297 | } |
298 | |
299 | /* Note: Don't test NumBlocksIsAlive, because it hasn't been set yet */ |
300 | if ( (!MyArray->ArraySizeIsAlive && MyArray->ArraySizeIsRegistered ) || |
301 | (!MyArray->UsedDeviceSizeIsAlive && MyArray->UsedDeviceSizeIsRegistered ) || |
302 | (!MyArray->PreferredMinorIsAlive && MyArray->PreferredMinorIsRegistered ) |
303 | ) { |
304 | print_error( "RECONFIGURE" ); |
305 | log_error( "Soft raid device disappeared" ); |
306 | return; |
307 | } |
308 | } |
309 | |
310 | void openMdstatFile() { |
311 | ssize_t n; |
312 | int fd; |
313 | |
314 | mdstatBuf[ 0 ] = '\0'; |
315 | if ( ( fd = open( "/proc/mdstat" , O_RDONLY ) ) < 0 ) |
316 | return; /* couldn't open /proc/mdstat */ |
317 | |
318 | n = read( fd, mdstatBuf, MDSTATBUFSIZE - 1 ); |
319 | close( fd ); |
320 | |
321 | if ( n == MDSTATBUFSIZE - 1 || n <= 0 ) { |
322 | log_error( "Internal buffer too small to read \'/proc/mdstat\'" ); |
323 | |
324 | return; |
325 | } |
326 | |
327 | mdstatBuf[ n ] = '\0'; |
328 | } |
329 | |
330 | ArrayInfo *getOrCreateArrayInfo(char *array_name, int array_name_length) { |
331 | ArrayInfo key; |
332 | INDEX idx; |
333 | ArrayInfo* MyArray; |
334 | /*We have the array name. see if we already have a record for it*/ |
335 | strncpy(key.ArrayName, array_name, array_name_length); |
336 | key.ArrayName[array_name_length]='\0'; |
337 | if ( ( idx = search_ctnr( ArrayInfos, ArrayInfoEqual, &key ) ) == 0 ) { |
338 | /* Found an existing array device */ |
339 | MyArray = get_ctnr( ArrayInfos, idx ); |
340 | } |
341 | else { |
342 | /* Found a new array device. Create a data structure for it. */ |
343 | MyArray = calloc(1,sizeof (ArrayInfo)); |
344 | if (MyArray == NULL) { |
345 | /* Memory could not be allocated, so print an error and exit. */ |
346 | fprintf(stderr, "Could not allocate memory\n" ); |
347 | exit(EXIT_FAILURE); |
348 | } |
349 | strcpy( MyArray->ArrayName, key.ArrayName ); |
350 | /* Add this array to our list of array devices */ |
351 | push_ctnr(ArrayInfos, MyArray); |
352 | char sensorName[128]; |
353 | sprintf(sensorName, "SoftRaid/%s/NumBlocks" , MyArray->ArrayName); |
354 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
355 | |
356 | sprintf(sensorName, "SoftRaid/%s/TotalDevices" , MyArray->ArrayName); |
357 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
358 | |
359 | sprintf(sensorName, "SoftRaid/%s/FailedDevices" , MyArray->ArrayName); |
360 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
361 | |
362 | sprintf(sensorName, "SoftRaid/%s/SpareDevices" , MyArray->ArrayName); |
363 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
364 | |
365 | sprintf(sensorName, "SoftRaid/%s/NumRaidDevices" , MyArray->ArrayName); |
366 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
367 | |
368 | sprintf(sensorName, "SoftRaid/%s/WorkingDevices" , MyArray->ArrayName); |
369 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
370 | |
371 | sprintf(sensorName, "SoftRaid/%s/ActiveDevices" , MyArray->ArrayName); |
372 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
373 | |
374 | sprintf(sensorName, "SoftRaid/%s/RaidType" , MyArray->ArrayName); |
375 | registerMonitor(sensorName, "string" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
376 | |
377 | sprintf(sensorName, "SoftRaid/%s/DeviceNumber" , MyArray->ArrayName); |
378 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
379 | |
380 | sprintf(sensorName, "SoftRaid/%s/ResyncingPercent" , MyArray->ArrayName); |
381 | registerMonitor(sensorName, "integer" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
382 | |
383 | sprintf(sensorName, "SoftRaid/%s/DiskInfo" , MyArray->ArrayName); |
384 | registerMonitor(sensorName, "listview" , printArrayAttribute, printArrayAttributeInfo, StatSM ); |
385 | |
386 | } |
387 | return MyArray; |
388 | } |
389 | |
390 | bool scanForArrays() { |
391 | char* mdstatBufP; |
392 | char* current_word; |
393 | int current_word_length = 0; |
394 | |
395 | ArrayInfo* MyArray; |
396 | |
397 | /* Mark all data as dead. As we find data, we'll mark it alive. */ |
398 | for ( MyArray = first_ctnr( ArrayInfos ); MyArray; MyArray = next_ctnr( ArrayInfos ) ) { |
399 | MyArray->Alive = false; |
400 | } |
401 | MyArray = NULL; |
402 | |
403 | openMdstatFile(); |
404 | |
405 | current_word = mdstatBufP = mdstatBuf; |
406 | |
407 | /* Process values from /proc/mdstat */ |
408 | |
409 | bool start = true; |
410 | while(mdstatBufP[0] != '\0') { |
411 | |
412 | if(!start) { |
413 | /*advanced one line at a time*/ |
414 | while( mdstatBufP[0] != '\0' && mdstatBufP[0] != '\n') mdstatBufP++; |
415 | mdstatBufP++; |
416 | } |
417 | start = false; |
418 | |
419 | if( mdstatBufP[0] == '\0') break; |
420 | current_word_length = 0; |
421 | current_word = mdstatBufP; |
422 | |
423 | |
424 | if(mdstatBufP[0]=='\n') |
425 | continue; |
426 | |
427 | if(mdstatBufP[0]=='#') /*skip comments */ |
428 | continue; |
429 | if (strncmp(current_word, "Personalities" , sizeof("Personalities" )-1)==0) |
430 | continue; |
431 | if (strncmp(current_word, "read_ahead" , sizeof("read_ahead" )-1)==0) |
432 | continue; |
433 | if (strncmp(current_word, "unused" , sizeof("unused" )-1)==0) |
434 | continue; |
435 | /* Better be an md line.. */ |
436 | if (strncmp(current_word, "md" , 2)!= 0) |
437 | continue; |
438 | int devnum; |
439 | if (strncmp(current_word, "md_d" , 4) == 0) |
440 | devnum = -1-strtoul(current_word+4, NULL, 10); |
441 | else /* it's md0 etc */ |
442 | devnum = strtoul(current_word+2, NULL, 10); |
443 | while( mdstatBufP[0] != '\0' &&mdstatBufP[0] != '\n' && mdstatBufP[0] != ' ' && mdstatBufP[0] != '\t') { |
444 | /*find the end of the word*/ |
445 | mdstatBufP++; |
446 | current_word_length++; |
447 | } |
448 | |
449 | MyArray = getOrCreateArrayInfo(current_word, current_word_length); |
450 | MyArray->Alive = true; |
451 | getMdadmDetail ( MyArray ); |
452 | MyArray->level = MyArray->pattern= NULL; |
453 | MyArray->ResyncingPercent = -1; |
454 | MyArray->IsCurrentlyReSyncing = false; |
455 | MyArray->devnum = devnum; |
456 | MyArray->ArrayActive = false; |
457 | MyArray->TotalDevices = MyArray->SpareDevices = MyArray->FailedDevices = 0; |
458 | MyArray->NumBlocks = 0; |
459 | |
460 | Disks *disk = MyArray->first_disk; |
461 | MyArray->first_disk = NULL; |
462 | Disks *next; |
463 | while(disk) { |
464 | next = disk->next; |
465 | free(disk); |
466 | disk = next; |
467 | } |
468 | |
469 | |
470 | /* In mdstat, we have something that looks like: |
471 | |
472 | md0 : active raid1 sda1[0] sdb1[1] |
473 | 312568576 blocks [2/2] [UU] |
474 | md1 : active raid1 sda2[0] sdb2[1] |
475 | 452568576 blocks [2/2] [UU] |
476 | |
477 | We have so far read in the "md0" bit, and now want to continue reading the details for this raid group until |
478 | we reach the next raid group which we note as starting with a non whitespace. |
479 | */ |
480 | char buffer[100]; |
481 | char status[100]; |
482 | status[0] = 0; |
483 | int harddisk_index; |
484 | for(;;) { |
485 | |
486 | while( mdstatBufP[0] != '\0' && ( (mdstatBufP[0] == '\n' && (mdstatBufP[1] == ' ' || mdstatBufP[1] == '\t')) || mdstatBufP[0] == ' ' || mdstatBufP[0] == '\t')) { |
487 | mdstatBufP++; /*Remove any whitespace first*/ |
488 | } |
489 | if( mdstatBufP[0] == '\0' || mdstatBufP[0] == '\n') { |
490 | break; /*we are now at the end of the file or line. Break this for loop*/ |
491 | } |
492 | |
493 | current_word=mdstatBufP; /*we are now pointing to the first non-whitespace of a word*/ |
494 | current_word_length=0; |
495 | while( mdstatBufP[0] != '\0' && mdstatBufP[0] != '\n' && mdstatBufP[0] != ' ' && mdstatBufP[0] != '\t') { |
496 | /*find the end of the word. We do this now so that we know the length of the word*/ |
497 | mdstatBufP++; |
498 | current_word_length++; |
499 | } |
500 | |
501 | char *eq; |
502 | int in_devs = 0; |
503 | int temp_int =0; |
504 | |
505 | |
506 | if (strncmp(current_word, "active" , sizeof("active" )-1)==0) |
507 | MyArray->ArrayActive = true; |
508 | else if (strncmp(current_word, "inactive" , sizeof("inactive" )-1)==0) |
509 | MyArray->ArrayActive = false; |
510 | else if (MyArray->ArrayActive >=0 && MyArray->level == NULL && current_word[0] != '(' && current_word[0] != ':' /*readonly*/) { |
511 | MyArray->level = strndup(current_word, current_word_length); |
512 | in_devs = 1; |
513 | |
514 | } else if (sscanf(current_word, "%d blocks " , &temp_int) == 1 ) { |
515 | MyArray->NumBlocks = temp_int; /* We have to do it via a temp_int variable otherwise we'll end up with nonsence if it's not found */ |
516 | } else if (in_devs && strncmp(current_word, "blocks" , sizeof("blocks" )-1)==0) |
517 | in_devs = 0; |
518 | #ifdef __GNUC__ |
519 | #warning in_devs cannot be != 0!! (CID 3228) |
520 | #endif |
521 | else if (in_devs && strncmp(current_word, "md" , 2)==0) { |
522 | /* This has an md device as a component. Maybe we should note this or something*/ |
523 | } else if(sscanf(current_word, "%[^[ ][%d]%[^ ]" , buffer, &harddisk_index, status) >= 2) { |
524 | /*Each device in the raid has an index. We can find the total number of devices in the raid by |
525 | simply finding the device with the highest index + 1. */ |
526 | if(harddisk_index >= MyArray->TotalDevices) MyArray->TotalDevices = harddisk_index+1; |
527 | Disks *new_disk = malloc(sizeof(Disks)); |
528 | new_disk->name = strdup(buffer); |
529 | new_disk->index = harddisk_index; |
530 | |
531 | |
532 | if(status[0] == '(') { |
533 | new_disk->status = status[1]; |
534 | if(status[1] == 'S') /*Spare hard disk*/ |
535 | MyArray->SpareDevices++; |
536 | else if(status[1] == 'F') |
537 | MyArray->FailedDevices++; |
538 | } else |
539 | new_disk->status = 'U'; |
540 | |
541 | /* insert the new disk into the linked list of disks*/ |
542 | new_disk->next = MyArray->first_disk; |
543 | MyArray->first_disk = new_disk; |
544 | |
545 | MyArray->NumRaidDevices = MyArray->TotalDevices - MyArray->FailedDevices; |
546 | status[0]=0; /*make sure we zero it again for next time*/ |
547 | } else if (!MyArray->pattern && |
548 | current_word[0] == '[' && |
549 | (current_word[1] == 'U' || current_word[1] == '_')) { |
550 | MyArray->pattern = strndup(current_word+1, current_word_length-1); |
551 | |
552 | if (MyArray->pattern[current_word_length-2]==']') |
553 | MyArray->pattern[current_word_length-2] = '\0'; |
554 | MyArray->ActiveDevices = MyArray->TotalDevices - MyArray->SpareDevices - MyArray->FailedDevices; |
555 | |
556 | MyArray->WorkingDevices=0; |
557 | int index=0; |
558 | for(;;) { |
559 | current_word++; |
560 | |
561 | if(current_word[0] == 'U') |
562 | MyArray->WorkingDevices++; |
563 | else if(current_word[0] == '_') { |
564 | Disks *disk = MyArray->first_disk; |
565 | while(disk) { |
566 | if(disk->index == index) { |
567 | if(disk->status == 'U') |
568 | disk->status = '_'; /* The disk hasn't failed, but is syncing */ |
569 | break; |
570 | } |
571 | disk = disk->next; |
572 | } |
573 | } else |
574 | break; |
575 | index++; |
576 | } |
577 | } else if (MyArray->ResyncingPercent == -1 && |
578 | strncmp(current_word, "re" , 2)== 0 && |
579 | current_word[current_word_length-1] == '%' && |
580 | (eq=strchr(current_word, '=')) != NULL ) { |
581 | MyArray->ResyncingPercent = atoi(eq+1); |
582 | if (strncmp(current_word,"resync" , 4)==0) |
583 | MyArray->IsCurrentlyReSyncing = true; |
584 | } else if (MyArray->ResyncingPercent == -1 && |
585 | strncmp(current_word, "resync" , 4)==0) { |
586 | MyArray->IsCurrentlyReSyncing = true; |
587 | } else if (MyArray->ResyncingPercent == -1 && |
588 | current_word[0] >= '0' && |
589 | current_word[0] <= '9' && |
590 | current_word[current_word_length-1] == '%') { |
591 | MyArray->ResyncingPercent = atoi(current_word); |
592 | } |
593 | /*ignore anything not understood*/ |
594 | } |
595 | } |
596 | |
597 | /* Look for dead arrays, and for NumBlocksIsRegistered */ |
598 | for ( MyArray = first_ctnr( ArrayInfos ); MyArray; MyArray = next_ctnr( ArrayInfos ) ) { |
599 | if ( MyArray->Alive == false ) { |
600 | print_error( "RECONFIGURE" ); |
601 | |
602 | log_error( "Soft raid device disappeared" ); |
603 | return false; |
604 | } |
605 | } |
606 | return true; |
607 | } |
608 | |
609 | /* =========== Public part =========== */ |
610 | |
611 | void initSoftRaid( struct SensorModul* sm ) { |
612 | StatSM = sm; |
613 | |
614 | ArrayInfos = new_ctnr(); |
615 | updateSoftRaid(); |
616 | } |
617 | |
618 | void exitSoftRaid( void ) { |
619 | destr_ctnr( ArrayInfos, free ); |
620 | } |
621 | |
622 | int updateSoftRaid( void ) { |
623 | scanForArrays(); |
624 | return 0; |
625 | } |
626 | |