> You can put the following script into your crontab at the frequency > you feel comfortable with. [...]
Or, if you prefer a short summary for humans, here's a script I wrote which is designed for that. It produces one line per configured RF unit. Sample output (this comes from a real live system - raid4 and raid7 are the ones which actually get used in this case): raid0: L1 /dev/sd0e /dev/sd1e raid1: L1 /dev/sd0h /dev/sd1h raid2: L1 /dev/sd2h /dev/sd3h raid3: L1 /dev/sd4h /dev/sd5h raid4: L0 /dev/raid1d /dev/raid2d /dev/raid3d raid5: L1 /dev/sd2e /dev/sd3e raid6: L1 /dev/sd4e /dev/sd5e raid7: L0 /dev/raid5d /dev/raid6d It still requires polling, and for automated error notification it needs to be wrapped in a "get current status, compare with previous, gripe on differences" wrapper. But it may be a useful ingredient, either as-is or with some hackery. The strings were written for 4.0.1's raidctl -s output. They may need fixing if yours looks different. /~\ The ASCII Mouse \ / Ribbon Campaign X Against HTML [email protected] / \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B #! /bin/sh # Public domain. sysctl -n hw.disknames | tr \ \\n | egrep \^raid | sort +0.4n | while read r do echo -n $r":" raidctl -s $r | awk 'BEGIN { in_disks = 0; in_spares = 0; nd = 0; havelevel[""] = 0; delete havelevel[""]; } /^Components:/ { in_disks = 1; next; } /^Spares:/ { in_spares = 1; in_disks = 0; next; } /^No spares/ { in_spares = 0; in_disks = 0; next; } /^Component label for / { in_disks = 0; in_spares = 0; curdisk = substr($4,1,length($4)-1); next; } /^ RAID Level:/ { raidlevel[curdisk] = $3; havelevel[$3] = 1; next; } /^Parity status:/ { parstat = $3; next; } /^Reconstruction is/ { recon = $3; next; } /^Parity Re-write/ { rewrite = $4; next; } /^Copyback is/ { cback = $3; next; } in_disks || in_spares { d = substr($1,1,length($1)-1); disks[nd] = d; $1 = ""; diskstate[d] = substr($0,2,length($0)-1); havestate[diskstate[d]] = 1; nd ++; } END { nlev = 0; for (x in havelevel) { nlev ++; lev = x; } if (nlev == 1) { printf(" L%s",lev); } for (i=0;i<nd;i++) { d = disks[i]; if ((d ~ /^component[0-9]*$/) && (diskstate[d] == "failed")) { continue; } printf(" %s",d); if (nlev != 1) printf("(L%s)",raidlevel[d]); if (diskstate[d] == "optimal") { } else if (diskstate[d] == "reconstructing") { if ("used_spare" in havestate) { printf("[failed-spared]"); } else { printf("[recon:%s]",recon); } } else if (diskstate[d] == "used_spare") { if ("reconstructing" in havestate) { printf("[spare:%s]",recon); } else { printf("[%s]",diskstate[d]); } } else { printf("[%s]",diskstate[d]); } } if ((recon != "100%") && !("reconstructing" in havestate)) { printf(" (recon %s)",recon); } if (rewrite != "100%") { printf(" (rewrite %s)",rewrite); } if (cback != "100%") { printf(" (copyback %s)",cback); } if ((parstat != "clean") && !((nd == 2) && ("1" in havelevel) && ((disks[0] ~ /^component[0-9]*$/) || (disks[1] ~ /^component[0-9]*$/)))) { printf(" (%s parity)",parstat); } printf("\n"); }' done
