Source:SwRaid

From FAIWiki

Jump to: navigation, search

Source code of the hook script for software raid support. Store this code in the $FAI/hooks/mountdisks.SW_RAID file.

#!/usr/bin/perl 
# BEGIN LICENCE BLOCK
#
# Copyright (C) 2005 Michal Svamberg <svamberg@civ.zcu.cz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
#
# END LICENCE BLOCK

# Usage:
# SW_RAID_CONFIG=mdX[
#           raid_level[,mdadm_option[,mdadm_option]
#          ]=deviceA[,deviceB][;spareX[,spareY]]
#          :mountpoint:[filesystem[,mkfs_options]:mount_options]:[boot]
#  
# Now supported this raids:
#   linear, raid0, stripe, raid1, mirror, raid5
# This filesystems are supported:
#   ext2, ext3, reiserfs, xfs, swap
#  
# Example:
# SW_RAID_CONFIG="md0[mirror,--chunk=16]=/dev/sda1,/dev/sdb1;/dev/sdc1:/:ext3,-T news:rw,errors=remount-ro:boot
#                 md1[raid0]=/dev/sda2,/dev/sdb2:/var:ext3:rw:"
#
# Records in configuration string are breaking by new line.
#
# Version: 0.0.8 (4.10.2007)
#
# ChangeLog:
# 0.0.8: fix mistake in name of disk_var.sh
# 0.0.7: fix missing diskvar variable in environment
# 0.0.6: fix error messages (__FILE__ and __LINE__ variables)
# 0.0.5: remove previously disabled wait_to_init()
# 0.0.4: mkfs.xfs is now called with -f option. 
#        You can now give mkfs options in SW_RAID_CONFIG, thanks Jonathon Blumenthal <jonblumenthal[at]gmail[dot]com>
#        Fix hash referencies, thanks Radoslav Bodo <bodik[at]civ[dot]zcu[dot]cz>
# 0.0.3: disabled wait_to_init(), thanks Rene Cunningham <rene[at]compounddata[dot]com>
#        set_partition_type() before create_md(), thanks Sebastien Estienne <sebastien[dot]estienne[at]gmail[dot]com>
# 0.0.2: add xfs support 

use strict;
use Data::Dumper;

my %config = ();
my $swaplist = "$ENV{SWAPLIST}";
# ------------------------------------------------------------------------
sub parse_config {
        my $var = shift;
        my $line;
        my $md;
        my $rest;
        my @opt;
        foreach $line (split /\n/, $var) {
                chomp $line;
                next if $line =~ /^\s*$/;
                next if $line =~ /^\s*#/;

                # md device, type
                $line =~ m#^(md[\d+])\[(linear|raid0|stripe|raid1|mirror|raid5),?(.*?)\]=(.*)$#
                         || die __FILE__,"[",__LINE__,"]: Error in SW_RAID_CONFIG at line: \n$line\n";
                $md = $1;
                $config{$md}{level} = $2;
                $config{$md}{options} = $3;
                $rest = $4;

                # options: --chunk=435,--verbose -> --chunk=435 --verbose
                if ($config{$md}{options}) {
                        $config{$md}{options} =~ s/,/ /g;
                }

                # rest (partitions, mount options)
                @opt = split /:/, $rest;
                # $opt[0]: devices (data & spare)
                ($config{$md}{devices}, $config{$md}{spares}) = split /;/, $opt[0], 2;
                $config{$md}{devices} =~ s/,/ /g;
                $config{$md}{num_devices} = split / /, $config{$md}{devices};

                if ($config{$md}{spares}) {
                        $config{$md}{spares} =~ s/,/ /g;
                        $config{$md}{num_spare} = split / /, $config{$md}{spares};
                }

                # $opt[1]: mountpoint
                $config{$md}{mountpoint} = $opt[1];

                # $opt[2]: filesystem
                        if ($opt[2] !~ /^(ext2|ext3|reiserfs|swap|xfs),?(.*?)$/) {
                        die __FILE__,"[",__LINE__,"]: Error in SW_RAID_CONFIG at line:\n$line\n  in filesystem: $opt[2]\n";
                }
                $config{$md}{filesystem} = $1;
                $config{$md}{filesystem_opt} = $2;

                # $opt[3]: mount options
                $config{$md}{mountoptions} = $opt[3] || 'defaults';

                # $opt[4]: boot
                $config{$md}{boot} = $opt[4];

                # changes for swap
                if ($config{$md}{filesystem} eq 'swap') {
                        $config{$md}{mountoptions} = 'sw';
                        $config{$md}{mountpoint} = 'none';
                        $swaplist .= "/dev/$md ";
                }
        }
}

# ----------------------------------------------------------------------
sub do_command {
        my $command = shift;
        my $result;

        print "$command\n";
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!        
        $result = `sh -c '$command'`;
        (($? >> 8) == 0) || (die "\nERROR:\n $result\n");
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        print $result;
}


# ----------------------------------------------------------------------
sub create_md {
        my $md;
        my $cmnd;
        foreach $md (sort keys %config) {
                $cmnd = "echo 'y' | mdadm --create $config{$md}{options} --verbose /dev/$md --level=$config{$md}{level} --raid-devices=$config{$md}{num_devices} $config{$md}{devices}";
                if ($config{$md}{spares}) {
                        $cmnd .= " --spare-devices=$config{$md}{num_spare} $config{$md}{spares}";
                }
                do_command($cmnd);
        }
}

# -----------------------------------------------------------------------
sub set_partition_type {
        my $md;
        my $cmnd;
        my $dev;
        my $devnum;

        foreach $md (sort keys %config) {
                foreach $dev (split / /, $config{$md}{devices}) {
                        $dev =~ /^(.*?)(\d+)$/;
                        $cmnd = "sfdisk --change-id $1 $2 fd";
                        do_command($cmnd);
                }
                foreach $dev (split / /, $config{$md}{spares}) {
                        $dev =~ /^(.*?)(\d+)$/;
                        $cmnd = "sfdisk --change-id $1 $2 fd";
                        do_command($cmnd);
                }
        }
}

# ------------------------------------------------------------------------
sub mkfs {
        my $md;
        my %trans = (
                'reiserfs' => 'mkfs.reiserfs -q',
                'ext3' => 'mkfs.ext3 -q',
                'ext2' => 'mkfs.ext2 -q',
                'swap' => 'mkswap',
                'xfs' => 'mkfs.xfs -q -f'
        );

        foreach $md (sort keys %config) {
                 do_command("$trans{$config{$md}{filesystem}} $config{$md}{filesystem_opt} /dev/$md");
        }
}

# ----------------------------------------------------------------------
sub update_fstab() {
        my @lines = ();
        my $i;
        my $md;
        my $nums;
        my $filename = "$ENV{LOGDIR}/fstab";
        my $comments = "";

        # read $target/etc/fstab
        open FILE, $filename || die __FILE__,"[",__LINE__,"]: Can't open $filename for read\n";
        @lines = <FILE>;
        close FILE;

        # remove comments
        $i = 0;
        while (($lines[$i] =~ /^#/) && ($i <= $#lines)) {
                $comments .= splice (@lines, $i, 1);
                next;
                $i++;
        }

        # remove old records
        print Data::Dumper->Dump([\@lines],['lines']);
        foreach $md (sort keys %config) {
LINE:          for ($i = 0; $i <= $#lines; $i++) {
                        # remove mountpoint
                        if (($lines[$i] =~ /\s+$config{$md}{mountpoint}\s+/) && ($lines[$i] !~ /swap/)) {
                                print "remove lines (mountpoints):\n '$config{$md}{mountpoint}' \n $lines[$i]\n";
                                splice (@lines, $i, 1);
                                redo LINE;
                        }
                        # remove all devices in raid
                        foreach (split / /, $config{$md}{devices}) {
                                if ($lines[$i] =~ /$_/) {
                                        print "remove lines (devices):\n '$_' \n $lines[$i]\n";
                                        splice (@lines, $i, 1);
                                        redo LINE;
                                }
                        }
                        # remove all devices as spare
                        foreach (split / /, $config{$md}{spares}) {
                                if ($lines[$i] =~ /$_/) {
                                        print "remove lines (spares):\n '$_' \n $lines[$i]\n";
                                        splice (@lines, $i, 1);
                                        redo LINE;
                                }
                        }
                }
        }

        # append new records
        foreach $md (sort keys %config) {
                $nums = ($config{$md}{mountpoint} eq 'none')?'0 0':'0 2';
                if ($config{$md}{mountpoint} eq '/') {
                        $nums = '0 1';
                        unshift @lines, "/dev/$md\t$config{$md}{mountpoint}\t$config{$md}{filesystem}\t$config{$md}{mountoptions}\t$nums\n";
                }
                else {
                        push @lines, "/dev/$md\t$config{$md}{mountpoint}\t$config{$md}{filesystem}\t$config{$md}{mountoptions}\t$nums\n";
                }
        }

        # save fstab
        open FILE, ">$filename" || die __FILE__,"[",__LINE__,"]: Can't open $filename for write\n";
        print FILE $comments;
        print FILE @lines;
        close FILE;

}

# -------------------------------------------------------------------------
sub update_diskvar {
        my $filename = "$ENV{LOGDIR}/disk_var.sh";
        my $lines = "";
        my $md;

        open FILE, $filename || die __FILE__,"[",__LINE__,"]: Can't open $filename for read\n";
        while ($_ = <FILE>){
                $lines .= $_;
        }
        close FILE;

        foreach $md (sort keys %config) {
                # ROOT_PARTITION
                if ($config{$md}{mountpoint} eq '/') {
                        $lines =~ s#^(.*)ROOT_PARTITION=\S+(.*)$#$1ROOT_PARTITION="/dev/$md"$2#s;
                }
        }
        # SWAPLIST
        $swaplist =~ s/^\s*(.*?)\s*$/$1/;
#        $lines =~ s#^(.*)SWAPLIST=\S+(.*)$#$1SWAPLIST="$swaplist"$2#s;
        $lines =~ s#^(.*)SWAPLIST=\".*?\"(.*)$#$1SWAPLIST="$swaplist"$2#s;

        open FILE, ">$filename" || die __FILE__,"[",__LINE__,"]: Can't open $filename for write\n";
        print FILE $lines;
        close FILE;
}

# ======================================================================

$ENV{SW_RAID_CONFIG} || die "Variable SW_RAID_CONFIG non exists.\n";
print "Configuration of SW_RAID:\n$ENV{SW_RAID_CONFIG}\n";
parse_config($ENV{SW_RAID_CONFIG});
print Data::Dumper->Dump([\%config],['config']);
set_partition_type();
create_md();
mkfs();
update_fstab();
update_diskvar();

exit 0;