Radix cross Linux Build System

Cross-platform build system is designed to build distributions of different operating systems for a set of target devices

39 Commits   2 Branches   2 Tags
     5         kx #!/bin/env perl
     5         kx 
     5         kx use FindBin;
     5         kx use lib $FindBin::Bin;
     5         kx 
     5         kx use strict;
     5         kx use warnings FATAL => 'all';
     5         kx 
     5         kx use POSIX;
     5         kx 
     5         kx use IO::Handle;
     5         kx use File::Basename;
     5         kx use File::Temp;
     5         kx use Getopt::Long;
     5         kx 
     5         kx use _kxLab;
     5         kx 
     5         kx #
     5         kx # Generate $(TARGET_BUILD_DIR)/HW.ext4fs file
     5         kx #
     5         kx # usage:
     5         kx #   $0 [options] topdir toolchain hardware flavour
     5         kx #
     5         kx # where:
     5         kx #      'topdir' - is a absolute path to the top directory of checked out branch
     5         kx #   'toolchain' - is a TOOLCHAIN name
     5         kx #    'hardware' - is a HARDWARE  name
     5         kx #     'flavour' - is a HARDWARE  variant
     5         kx #
     5         kx 
     5         kx my ($rootfs_dest_dir, $products_dest_dir, $devices_file);
     5         kx my ($top_dir, $toolchain, $hardware, $flavour, $target_build_dir);
     5         kx my ($size, $rootfs_base_dir, $products_base_dir);
     5         kx 
     5         kx #
     5         kx # Default values:
     5         kx #
     5         kx my $default_requested_size = "4.1G";
     5         kx my $reserved_space_coeff   =  0.4;
     5         kx #
     5         kx # Constants:
     5         kx #
     5         kx my $SDHC_blksz   = 524288;
     5         kx my $SDHC_min_blks  = 4224;
     5         kx my $GiB      = 1073741824;
     5         kx my $MiB      =    1048576;
     5         kx my $KiB      =       1024;
     5         kx 
     5         kx #
     5         kx # File systems UUIDs:
     5         kx # ==================
     5         kx #
     5         kx #  prep  : 'кросс:prep :парт' : eaf0eef1-f13a-7072-6570-203aefe0f0f2
     5         kx #  uefi  : 'кросс:uefi :парт' : eaf0eef1-f13a-7565-6669-203aefe0f0f2
     5         kx #  boot  : 'кросс:boot :парт' : eaf0eef1-f13a-626F-6F74-203aefe0f0f2
     5         kx #  boot0 : 'кросс:boot0:парт' : eaf0eef1-f13a-626F-6F74-303aefe0f0f2
     5         kx #  boot1 : 'кросс:boot1:парт' : eaf0eef1-f13a-626F-6F74-313aefe0f0f2
     5         kx #  root  : 'кросс:root :парт' : eaf0eef1-f13a-726F-6F74-203aefe0f0f2
     5         kx #  root0 : 'кросс:root0:парт' : eaf0eef1-f13a-726F-6F74-303aefe0f0f2
     5         kx #  root1 : 'кросс:root1:парт' : eaf0eef1-f13a-726F-6F74-313aefe0f0f2
     5         kx #  home  : 'кросс:home :парт' : eaf0eef1-f13a-686F-6D65-203aefe0f0f2
     5         kx #  opt   : 'кросс:opt  :парт' : eaf0eef1-f13a-6F70-7420-203aefe0f0f2
     5         kx #  usr   : 'кросс:usr  :парт' : eaf0eef1-f13a-7573-7220-203aefe0f0f2
     5         kx #  var   : 'кросс:var  :парт' : eaf0eef1-f13a-7661-7220-203aefe0f0f2
     5         kx #  swap  : 'кросс:swap :парт' : eaf0eef1-f13a-7376-6170-203aefe0f0f2
     5         kx #
     5         kx my $BOOT_UUID = "eaf0eef1-f13a-626F-6F74-203aefe0f0f2";
     5         kx my $ROOT_UUID = "eaf0eef1-f13a-726F-6F74-203aefe0f0f2";
     5         kx my $HOME_UUID = "eaf0eef1-f13a-686F-6D65-203aefe0f0f2";
     5         kx 
     5         kx #
     5         kx # NOTE:
     5         kx # ====
     5         kx #   Вообще размер создаваемой файловой системы выбирается кратным
     5         kx #   величине SDHC блока. Это позволяет не задумываться о геометрии
     5         kx #   целевого носителя, а также, о выравнивании разделов по границе
     5         kx #   4096 байтов.
     5         kx #
     5         kx 
     5         kx #
     5         kx # To be calculated:
     5         kx #
     5         kx my $rootfs_in_bytes;
     5         kx my ($size_in_bytes, $size_in_1K_blks, $size_in_SDHC_blks);
     5         kx 
     5         kx 
     5         kx sub usage
     5         kx {
     5         kx   print <<EOF;
     5         kx 
     5         kx Usage: build_ext4fs [options] topdir toolchain hardware [flavour]
     5         kx Options:
     5         kx   -s, --size=<size{K|M|G}>
     5         kx                  - where <size> is a number of GiB, MiB, or KiB
     5         kx                    (Note that {K|M|G} shoud follow without spaces);
     5         kx 
     5         kx   -r, --rootfs-dir=<DIR>
     5         kx                  - base name of rootfs dir default value is 'rootfs';
     5         kx 
     5         kx Args:
     5         kx           topdir - is a absolute path to the top of checked out branch;
     5         kx        toolchain - is a TOOLCHAIN name;
     5         kx         hardware - is a HARDWARE name.
     5         kx          flavour - is a HARDWARE variant.
     5         kx 
     5         kx EOF
     5         kx   exit;
     5         kx }
     5         kx 
     5         kx #
     5         kx # returns directory size in bytes:
     5         kx #
     5         kx sub directory_size
     5         kx {
     5         kx   my $dir = shift;
     5         kx   my $size;
     5         kx 
     5         kx   if( ! defined $dir or $dir eq "" ) { $dir = "."; }
     5         kx 
     5         kx   $size = `du -s -B 1 $dir | cut -f1 -d'\t'`;  chomp( $size );
     5         kx 
     5         kx   return $size;
     5         kx }
     5         kx 
     5         kx #
     5         kx # Calculate dest rootfs image size according to
     5         kx # requested size (argument) and size of rootfs.
     5         kx #
     5         kx #  size_arg - requested size;
     5         kx #  src_size - the size of rootfs directory.
     5         kx #
     5         kx sub calculate_sizes
     5         kx {
     5         kx   my  $size_arg = shift;
     5         kx   my  $src_size = shift;
     5         kx 
     5         kx   my ($min_size, $z, $m);
     5         kx 
     5         kx   #
     5         kx   # Initial Size = source rootfs size + reserved space:
     5         kx   #
     5         kx   $min_size = floor( $src_size + $src_size * $reserved_space_coeff );
     5         kx   $z        = $min_size;
     5         kx 
     5         kx   #
     5         kx   # File System Size:
     5         kx   #
     5         kx   if( $size_arg =~ m!^([0-9.]+)([GKM]{0,1})!gm )
     5         kx   {
     5         kx     my ($rsz, $mul) = ($1, $2);
     5         kx 
     5         kx     if( defined $mul )
     5         kx     {
     5         kx       if   ( $mul eq "G" ) { $m = $GiB; }
     5         kx       elsif( $mul eq "M" ) { $m = $MiB; }
     5         kx       elsif( $mul eq "K" ) { $m = $KiB; }
     5         kx       else                 { $m =    1; }
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       $m = 1;
     5         kx     }
     5         kx     $z = $rsz * $m;
     5         kx     $z = floor( $z );
     5         kx 
     5         kx     if( $z < $min_size ) { $z = $min_size; }
     5         kx   }
     5         kx 
     5         kx   if( $z > $SDHC_blksz ) { $size_in_SDHC_blks = ceil( $z / $SDHC_blksz ); }
     5         kx   else                   { $size_in_SDHC_blks = 1; }
     5         kx 
     5         kx   if( $size_in_SDHC_blks < $SDHC_min_blks ) { $size_in_SDHC_blks = $SDHC_min_blks; }
     5         kx 
     5         kx   $size_in_bytes   = $size_in_SDHC_blks * $SDHC_blksz;
     5         kx   $size_in_1K_blks = $size_in_bytes / $KiB;
     5         kx }
     5         kx 
     5         kx 
     5         kx #
     5         kx # Parse the command line options
     5         kx #
     5         kx $size = $default_requested_size;
     5         kx if( ! GetOptions( 's=s' => \$size,
     5         kx                   'size=s' => \$size,
     5         kx                   'r=s' => \$rootfs_base_dir,
     5         kx                   'rootfs-dir=s' => \$rootfs_base_dir,
     5         kx                   'p=s' => \$products_base_dir,
     5         kx                   'products-dir=s' => \$products_base_dir,
     5         kx                   'help|h|?'  => sub { usage() }
     5         kx                 )
     5         kx   )
     5         kx {
     5         kx   usage();
     5         kx }
     5         kx 
     5         kx # Get the rest of the command line
     5         kx my $topdir = shift;
     5         kx 
     5         kx $toolchain = shift;
     5         kx $hardware  = shift;
     5         kx $flavour   = shift;
     5         kx 
     5         kx if( ! defined $size or $size eq "" ) { $size = $default_requested_size; }
     5         kx 
     5         kx if( ! defined $rootfs_base_dir   or $rootfs_base_dir   eq "" ) { $rootfs_base_dir     = "rootfs";   }
     5         kx if( ! defined $products_base_dir or $products_base_dir eq "" ) { $products_base_dir   = "products"; }
     5         kx 
     5         kx if( ! defined $topdir    or $topdir eq "" )    { usage; }
     5         kx if( ! defined $toolchain or $toolchain eq "" ) { usage; }
     5         kx if( ! defined $hardware  or $hardware eq "" )  { usage; }
     5         kx 
     5         kx 
     5         kx if( ! defined $flavour   or $flavour eq "" )
     5         kx {
     5         kx   $flavour = "";
     5         kx   $target_build_dir  = "." . $toolchain . "/" . $hardware;
     5         kx   $rootfs_dest_dir   = $topdir . "/dist/" . $rootfs_base_dir . "/" . $toolchain . "/" . $hardware;
     5         kx }
     5         kx else
     5         kx {
     5         kx   $target_build_dir  = "." . $toolchain . "/" . $hardware . "/" . $flavour;
     5         kx   $rootfs_dest_dir   = $topdir . "/dist/" . $rootfs_base_dir . "/" . $toolchain . "/" . $hardware . "/" . $flavour;
     5         kx }
     5         kx 
     5         kx $products_dest_dir   = $topdir . "/dist/" . $products_base_dir . "/" . $toolchain . "/" . $hardware;
     5         kx 
     5         kx # setup $top_build_dir
     5         kx $top_dir = $topdir;
     5         kx my $build_system = $top_dir . "/build-system";
     5         kx 
     5         kx _kxLab::system( "mkdir -p $target_build_dir" );
     5         kx 
     5         kx #
     5         kx # The .DEVTABLE shoul be created in TARGET_BUILD_DIR.
     5         kx #
     5         kx $devices_file = $target_build_dir . "/" . ".DEVTABLE";
     5         kx 
     5         kx _kxLab::error( "build_ext4fs: $topdir is not a directory" ) if( ! -d $topdir );
     5         kx _kxLab::error( "build_ext4fs: .DEVTABLE missing: $devices_file" ) if ( ! -f $devices_file );
     5         kx 
     5         kx 
     5         kx $rootfs_in_bytes = directory_size( $rootfs_dest_dir );
     5         kx calculate_sizes( $size, $rootfs_in_bytes);
     5         kx 
     5         kx ################ debug ################
     5         kx #
     5         kx # root_src - only for log messages:
     5         kx #
     5         kx my $root_src = $rootfs_dest_dir;
     5         kx if( $rootfs_dest_dir =~ m!$top_dir/(.+)! )
     5         kx {
     5         kx   $root_src = $1;
     5         kx }
     5         kx print "#######   requested size          = '" . $size . "';\n";
     5         kx print "#######\n";
     5         kx print "####### SOURCE:\n";
     5         kx print "####### ------\n";
     5         kx print "#######   rootfs source           = '" . $root_src . "';\n";
     5         kx print "#######   rootfs size_in_bytes    = '" . $rootfs_in_bytes . "';\n";
     5         kx print "#######\n";
     5         kx print "####### TARGET:\n";
     5         kx print "####### ------\n";
     5         kx print "#######   image size_in_bytes     = '" . $size_in_bytes . "';\n";
     5         kx print "#######   image size_in_1K_blks   = '" . $size_in_1K_blks . "';\n";
     5         kx print "#######   image size_in_SDHC_blks = '" . $size_in_SDHC_blks . "';\n";
     5         kx ############# end of debug ############
     5         kx 
     5         kx my $ext4fs_file = $target_build_dir . "/" . $hardware . ".ext4fs";
     5         kx my $ext2fs_file = $target_build_dir . "/" . $hardware . ".ext2fs";
     5         kx 
     5         kx my $MKE4FS = $ENV{MKE4FS};
     5         kx if( ! defined $MKE4FS or $MKE4FS eq "" )
     5         kx {
     5         kx   $MKE4FS = "/sbin/mkfs.ext4";
     5         kx }
     5         kx my $E4FSCK = $ENV{E4FSCK};
     5         kx if( ! defined $E4FSCK or $E4FSCK eq "" )
     5         kx {
     5         kx   $E4FSCK = "/sbin/fsck.ext4";
     5         kx }
     5         kx my $POPULATEFS = $ENV{POPULATEFS};
     5         kx if( ! defined $POPULATEFS or $POPULATEFS eq "" )
     5         kx {
     5         kx   $POPULATEFS = $build_system . "/sbin/populatefs";
     5         kx }
     5         kx my $GENEXT2FS = $ENV{GENEXT2FS};
     5         kx if( ! defined $GENEXT2FS or $GENEXT2FS eq "" )
     5         kx {
     5         kx   $GENEXT2FS = $build_system . "/sbin/genext2fs";
     5         kx }
     5         kx 
     5         kx 
     5         kx my $label = $hardware;
     5         kx 
     5         kx #my $rootfs_maxnode_arg = "-N 1073741824";
     5         kx my $rootfs_maxnode_arg = "";
     5         kx 
     5         kx my $rootfs_reserved_pst_arg = "-m 5";
     5         kx 
     5         kx _kxLab::system( "dd if=/dev/zero of=$ext4fs_file"        .
     5         kx                 "   seek=$size_in_1K_blks count=0 bs=1k" .
     5         kx                 "   1> /dev/null 2> /dev/null" );
     5         kx 
     5         kx _kxLab::system( $MKE4FS .
     5         kx                 " -F -E root_owner=0:0 -L $label -U $ROOT_UUID" .
     5         kx                                          " $rootfs_maxnode_arg" .
     5         kx                        " -O has_journal,ext_attr,resize_inode," .
     5         kx                            "dir_index,filetype,extent,flex_bg," .
     5         kx                            "sparse_super,large_file,uninit_bg," .
     5         kx                                   "dir_nlink,extra_isize,64bit" .
     5         kx                        " $rootfs_reserved_pst_arg $ext4fs_file" );
     5         kx 
     5         kx _kxLab::system( $POPULATEFS .
     5         kx                 " -U -d $rootfs_dest_dir -D $devices_file" .
     5         kx                 " $ext4fs_file" );
     5         kx 
     5         kx #######
     5         kx ####### skip message that the file system was modified:
     5         kx #######
     5         kx _kxLab::system( $E4FSCK .
     5         kx                 " -fy"  .
     5         kx                 " $ext4fs_file 1>/dev/null 2>/dev/null ; exit 0" );
     5         kx 
     5         kx 
     5         kx #################################################################################
     5         kx #######
     5         kx ####### Also the Ext2 Root FS image can be created by `genext2fs' utility.
     5         kx #######
     5         kx #  _kxLab::system( $GENEXT2FS .
     5         kx #                  " -U -B 1024 -b $size_in_1K_blks $rootfs_reserved_pst_arg" .
     5         kx #                  " -d $rootfs_dest_dir -D $devices_file $ext2fs_file" );
     5         kx #######
     5         kx #######
     5         kx #################################################################################
     5         kx 
     5         kx 
     5         kx #################################################################################
     5         kx #######
     5         kx ####### Simple MBR for SDHC cards with one primary Linux partition:
     5         kx #######
     5         kx sub partition_record
     5         kx {
     5         kx   my $type          = shift;
     5         kx   my $active        = shift;
     5         kx   my $sector_size   = shift;
     5         kx   my $track_size    = shift;
     5         kx   my $cylinder_size = shift;
     5         kx   my $skip_size     = shift;
     5         kx   my $disk_size     = shift;
     5         kx 
     5         kx   my ($part0, $part1, $part2, $part3);
     5         kx 
     5         kx   my ($c, $h, $s, $p, $q);
     5         kx 
     5         kx   ################ debug ################
     5         kx   if( $type == 0x0C ) { print "#######   === Primary W95 FAT32 (LBA) Partition:\n"; }
     5         kx   else                { print "#######   === Primary Linux Partition:\n";           }
     5         kx   ############# end of debug ############
     5         kx 
     5         kx   #
     5         kx   # Calculate CHS Start Address (assume 1Mib offset):
     5         kx   #
     5         kx   $c = floor( $skip_size / $cylinder_size );
     5         kx   $p = $skip_size % $cylinder_size;
     5         kx   $h = floor( $p / $track_size );
     5         kx   $q = $p % $track_size;
     5         kx   $s = floor( $q / $sector_size ) + 1;
     5         kx 
     5         kx   $part0 = $active; # if 0x80 then the partition is active
     5         kx   $part0 = $part0 | ( $h & 0x000000ff ) <<  8;
     5         kx   $part0 = $part0 | ( $s & 0x0000003f ) << 16;
     5         kx   $part0 = $part0 | ( ( $c & 0x00000030 ) >> 8 ) << 22;
     5         kx   $part0 = $part0 | ( $c & 0x000000ff ) << 24;
     5         kx 
     5         kx   ################ debug ################
     5         kx   print "#######   CHS Start Address       = ($c/$h/$s);\n";
     5         kx   ############# end of debug ############
     5         kx 
     5         kx   #
     5         kx   # Calculate CHS End Address (assume 1Mib offset):
     5         kx   #
     5         kx   $c = floor( ($disk_size - $sector_size) / $cylinder_size );
     5         kx   $p = ($disk_size - $sector_size) % $cylinder_size;
     5         kx   $h = floor( $p / $track_size );
     5         kx   $q = $p % $track_size;
     5         kx   $s = floor( $q / $sector_size ) + 1;
     5         kx 
     5         kx   $part1 = $type; # Partition type [0x83 - Linux; 0x0C - W95 FAT32 (LBA)]
     5         kx   $part1 = $part1 | ( $h & 0x000000ff ) <<  8;
     5         kx   $part1 = $part1 | ( $s & 0x0000003f ) << 16;
     5         kx   $part1 = $part1 | ( ( $c & 0x00000300 ) >> 8 ) << 22;
     5         kx   $part1 = $part1 | ( $c & 0x000000ff ) << 24;
     5         kx 
     5         kx   ################ debug ################
     5         kx   print "#######   CHS End Address         = ($c/$h/$s);\n";
     5         kx   ############# end of debug ############
     5         kx 
     5         kx   my $lba;
     5         kx   #
     5         kx   # Calculate LBA Start Address [assume 1048576 byte (2048 sectors) offset]:
     5         kx   #
     5         kx   $lba = floor( $skip_size / $sector_size );
     5         kx   $part2 = $lba;
     5         kx   ################ debug ################
     5         kx   print "#######   LBA Start Address       = $lba;\n";
     5         kx   ############# end of debug ############
     5         kx 
     5         kx   #
     5         kx   # calculate LBA numbers  (1Mib offset):
     5         kx   #
     5         kx   $lba = floor( ($disk_size - $skip_size) / $sector_size );
     5         kx   $part3 = $lba;
     5         kx   ################ debug ################
     5         kx   print "#######   LBA sectors             = $lba;\n";
     5         kx   ############# end of debug ############
     5         kx 
     5         kx   return ( $part0, $part1, $part2, $part3 );
     5         kx }
     5         kx 
     5         kx #
     5         kx # Check if the boot-records and may be FAT32 partition are created by U-Boot:
     5         kx #
     5         kx my $fat32_size   = 0;
     5         kx my $records_size = 0;
     5         kx my $FAT32_file   = $products_dest_dir . "/" . $hardware . ".fat32fs";
     5         kx my $records_file = $products_dest_dir . "/" . $hardware . ".boot-records";
     5         kx if( -f $FAT32_file   ) { $fat32_size   = -s $FAT32_file;   }
     5         kx if( -f $records_file ) { $records_size = -s $records_file; }
     5         kx 
     5         kx 
     5         kx my $MBR_file = $target_build_dir . "/" . $hardware . ".SD.MBR";
     5         kx 
     5         kx my $heads             =   4;
     5         kx my $sectors_per_track =  16;
     5         kx my $sector_size       = 512;
     5         kx my $track_size        = $sector_size * $sectors_per_track;
     5         kx 
     5         kx my $cylinder_size = $heads * $sectors_per_track * $sector_size;
     5         kx my $cylinders     = $size_in_bytes / $cylinder_size;
     5         kx my $skip_size     = $MiB;
     5         kx my $disk_size;
     5         kx 
     5         kx if( $records_size > $skip_size ) { $skip_size = $records_size; }
     5         kx 
     5         kx ################ debug ################
     5         kx print "#######\n";
     5         kx print "####### Master Boot Record:\n";
     5         kx print "####### ------------------\n";
     5         kx ############# end of debug ############
     5         kx 
     5         kx my ($part0, $part1, $part2, $part3);
     5         kx 
     5         kx #
     5         kx # The first partition is always active
     5         kx #
     5         kx if( $fat32_size > 0 )
     5         kx {
     5         kx   $disk_size = $skip_size + $fat32_size;
     5         kx 
     5         kx   ($part0, $part1, $part2, $part3) =
     5         kx     partition_record( 0x0C,
     5         kx                       0x80,
     5         kx                       $sector_size,
     5         kx                       $track_size,
     5         kx                       $cylinder_size,
     5         kx                       $skip_size,
     5         kx                       $disk_size );
     5         kx 
     5         kx   $skip_size = $skip_size + $fat32_size;
     5         kx }
     5         kx else
     5         kx {
     5         kx   $disk_size = $skip_size + $size_in_bytes;
     5         kx 
     5         kx   ($part0, $part1, $part2, $part3) =
     5         kx     partition_record( 0x83,
     5         kx                       0x80,
     5         kx                       $sector_size,
     5         kx                       $track_size,
     5         kx                       $cylinder_size,
     5         kx                       $skip_size,
     5         kx                       $disk_size );
     5         kx }
     5         kx 
     5         kx my $zero = 0;
     5         kx my $sign = 0xaa55;
     5         kx 
     5         kx #
     5         kx # The documentation about packing binary date is available at:
     5         kx #
     5         kx #    http://perldoc.perl.org/functions/pack.html
     5         kx #
     5         kx #  We are using Little endian 16-bit and 32-bit data.
     5         kx #
     5         kx #  MBR Info can be found, for example at:
     5         kx #  -------------------------------------
     5         kx #    https://en.wikipedia.org/wiki/Master_boot_record
     5         kx #    https://en.wikipedia.org/wiki/Master_boot_record#PTE
     5         kx #
     5         kx open( MBR, '>', $MBR_file) or _kxLab::error( "build_ext4fs: Could not open $MBR_file file: $!" );
     5         kx binmode( MBR );
     5         kx 
     5         kx #
     5         kx # Fill first 446 bytes of MBR:
     5         kx #
     5         kx for ( my $n = 0; $n < 111; ++$n ) { print MBR pack( 'L<', $zero ); }
     5         kx print MBR pack( 'S<', $zero );
     5         kx 
     5         kx #
     5         kx # First primary partition:
     5         kx #
     5         kx print MBR pack( 'L<', $part0 );
     5         kx print MBR pack( 'L<', $part1 );
     5         kx print MBR pack( 'L<', $part2 );
     5         kx print MBR pack( 'L<', $part3 );
     5         kx 
     5         kx if( $fat32_size > 0 )
     5         kx {
     5         kx   $disk_size = $skip_size + $size_in_bytes;
     5         kx 
     5         kx   ($part0, $part1, $part2, $part3) =
     5         kx     partition_record( 0x83,
     5         kx                       0x00,
     5         kx                       $sector_size,
     5         kx                       $track_size,
     5         kx                       $cylinder_size,
     5         kx                       $skip_size,
     5         kx                       $disk_size );
     5         kx   #
     5         kx   # Second primary partition:
     5         kx   #
     5         kx   print MBR pack( 'L<', $part0 );
     5         kx   print MBR pack( 'L<', $part1 );
     5         kx   print MBR pack( 'L<', $part2 );
     5         kx   print MBR pack( 'L<', $part3 );
     5         kx 
     5         kx }
     5         kx else
     5         kx {
     5         kx   #
     5         kx   # There is no Second Partition
     5         kx   #
     5         kx   for ( my $n = 0; $n < 4; ++$n )
     5         kx   {
     5         kx     print MBR pack( 'L<', $zero );
     5         kx   }
     5         kx }
     5         kx 
     5         kx #
     5         kx # Two zero primary partitions:
     5         kx #
     5         kx for ( my $n = 0; $n < 8; ++$n )
     5         kx {
     5         kx   print MBR pack( 'L<', $zero );
     5         kx }
     5         kx 
     5         kx #
     5         kx # Boot Signature:
     5         kx #
     5         kx print MBR pack( 'S<', $sign );
     5         kx 
     5         kx close( MBR );
     5         kx 
     5         kx #######
     5         kx ####### End of Simple MBR writing.
     5         kx #######
     5         kx #################################################################################