~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to ksysguard/ksysguardd/Linux/softraid.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}