Rev 4773 | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### Copyright (C) 2008 ERG Limited, All rights reserved## Module name : Proc_day0fs_script.pl# Module type : Makefile system# Compiler(s) : Perl# Environment(s): jats## Description :## Usage:##......................................................................#require 5.008_002;use strict;use warnings;use Pod::Usage;use Getopt::Long;use File::Path;use File::Copy;use FindBin; # Determine the current directoryuse lib "$FindBin::Bin"; # Allow Modules in current directoryuse JatsError;use JatsSystem;use FileUtils;use JatsCopy qw(SetCopyDirDefaults DeleteDir CopyDir CreateDir);use CreateSdImage qw( CreateSdImage );### Global Variables#my $VERSION = 1.0;our $AUTOLOAD;my $BUILD = 'build'; # Build subdirmy $WORK = "${BUILD}/image";my $source_specified = 0; # Ensure that source is specifiedmy $output_image = 0; # Ensure output is specifiedmy $output_sd = 0;## Command line options#my $opt_debug = $ENV{'GBE_DEBUG'}; # Allow global debugmy $opt_verbose = $ENV{'GBE_VERBOSE'}; # Allow global verbosemy $opt_vargs; # Verbose argmy $opt_help = 0;my $opt_manual = 0;my $opt_clean = 0;my $opt_platform;my $opt_type;my $opt_buildname;my $opt_packagedir;my $opt_interfacedir;my $opt_compilerpath;my $opt_product;my $opt_packagebindir;our $opt_buildroot;my $opt_target;my $opt_version;my $opt_userscript;#-------------------------------------------------------------------------------# Function : Mainline Entry Point## Description :## Inputs :#my $result = GetOptions ("help+" => \$opt_help,"manual" => \$opt_manual,"verbose:s" => \$opt_vargs,"clean" => \$opt_clean,"Platform=s" => \$opt_platform,"Type=s" => \$opt_type,"BuildName=s" => \$opt_buildname,"PackageDir=s" => \$opt_packagedir,"InterfaceDir=s" => \$opt_interfacedir,"CompilerPath=s" => \$opt_compilerpath,"Product=s" => \$opt_product,"PackageBinDir=s" => \$opt_packagebindir,"BuildRoot=s" => \$opt_buildroot,"Target=s" => \$opt_target,"BuildVersion=s" => \$opt_version,"UserScript=s" => \$opt_userscript,);## Process help and manual options#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);pod2usage(-verbose => 1) if ($opt_help == 2 );pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));## Configure the error reporting process now that we have the user options#$opt_verbose++ unless ( $opt_vargs eq '@' );ErrorConfig( 'name' => 'Proc_Day0fs','verbose' => $opt_verbose );## Configure the System command to fail on any error#SystemConfig ( ExitOnError => 1 );SetCopyDirDefaults ( 'EmptyDirs' => 1 ,Log => 0 );## Init the FileSystem Uiltity interface#InitFileUtils();## Ensure that we have all required options#Error ("CompilePath not set") unless ( $opt_compilerpath );Error ("Platform not set") unless ( $opt_platform );Error ("Type not set") unless ( $opt_type );Error ("BuildName not set") unless ( $opt_buildname );Error ("PackageBinDir not set") unless ( $opt_packagebindir );Error ("InterfaceDir not set") unless ( $opt_interfacedir );Error ("CompilePath not set") unless ( $opt_compilerpath );Error ("Product not set") unless ( $opt_product );Error ("BuildRoot not set") unless ( $opt_buildroot );Error ("Target not set") unless ( $opt_target );Error ("User Script not set") unless ( $opt_userscript );## Calculate a few paths#my $TOOLSUITE = $opt_compilerpath;$TOOLSUITE =~ s~^.*/~~;$TOOLSUITE =~ s~-gcc$~~;my $CROSSLIBS = $opt_compilerpath;$CROSSLIBS =~ s~/bin/.*$~~;$CROSSLIBS .= "/${TOOLSUITE}/lib";my $CROSSEXE = $opt_compilerpath;$CROSSEXE =~ s~/bin/.*$~~;$CROSSEXE .= "/${TOOLSUITE}";my $CROSS_COMPILE = $opt_compilerpath;$CROSS_COMPILE =~ s~gcc$~~;my $CROSS_OBJCOPY = ${CROSS_COMPILE} . "objcopy";## Display variables used#Message "======================================================================";Message "Build day0 file system";Message " Package: ${opt_buildname}";Message " Version: ${opt_version}";Message " Building for: ${opt_platform}, $opt_target";Message " Product: ${opt_product}";Message " Type: ${opt_type}";Message " Script: ${opt_userscript}";Verbose " Verbose: ${opt_verbose}";Message " BuildRoot: ${opt_buildroot}";Verbose " BuildRoot: ${opt_buildroot}";Verbose " InterfaceDir: ${opt_interfacedir}";Verbose " CROSS_COMPILE: ${CROSS_COMPILE}";Verbose " CROSSLIBS: ${CROSSLIBS}";Verbose " CROSS_OBJCOPY: ${CROSS_OBJCOPY}";Message "======================================================================";## Perform Clean up# Invoked during "make clean" or "make clobber"#if ( $opt_clean ){Message ("Remove build directory: $BUILD");rmtree( $BUILD );exit;}## Have setup the basics# Invoke the user script to drive the remainder of the process# The script should only contain known directives# The directives will build up data structures that will be processed# after the script has been read##Message ("Process User Script: $opt_userscript");Error ("Board Specfic file Not found: $opt_userscript") unless ( -f $opt_userscript );require $opt_userscript;## The process of requiring the user script# will have done all the required work# Perform minor sanity testing### All done#Error ( "No package output specified" )unless ( $output_image || $output_sd );exit 0;################################################################################################################################################################## The following functions are intended to be used to manipulate files within# the output image.## These may be used by the board specfic functions.##################################################################################-------------------------------------------------------------------------------# Function : Day0Source## Description : Determine the source of the Day0 File System# Use of this directive is mandatory### Inputs : Options# --Dir=name - Source dir# --Image=name - Source image## Returns : Nothing#sub Day0Source{my ($opt) = @_;## Can only use this directive ONCE#Error ("Multiple Day0Source directives not allowed")if ( $source_specified++ );## Start with a clean slate#DeleteDir ( $WORK );## Process options#if ( $opt =~ /^--Dir=(.+)/ ) {## User has specified a directory# Copy the entire directory to the work area#Message ("Copy in Day0 source directory: $WORK");CopyDir ( $1, $WORK, 'DeleteFirst' => 1 );} elsif ( $opt =~ /^--Image=(.+)/ ) {## User has specified an Image# Locate the image and extract it into the work area#my $name = $1;Message ("Extract File System Image: $name");## File will come from a Package# This is where the tool places output files#my $fname = Internal::LocateFile ('bin', $name . '.tgz' );Error ("Cannot locate Day0 source image: $name")unless $fname;## Create a Tar command# Assumes the presence of a GNU style tar#CreateDir ( $WORK );System ( 'tar','--extract','--file', $fname,'--gzip',IsVerbose(1) ? ( '--verbose' ) : (),'--directory', $WORK,);} else {Error ("Unknown Day0Source option: $opt");}}#-------------------------------------------------------------------------------# Function : Day0Operation## Description : Perform one of the special Day0 Operations## Inputs : $subfunction - Sub function to perform# @opts - Sub function options## Returns : Nothing#sub Day0Operation{Error ("Day0Source must be specified first")unless ( $source_specified );## Perform the Day0Operation# These are specialised operations and normally only performed on the# the basic skelton.## Dispatch to the required function#my $opt = shift (@_);if ( my $fref = UNIVERSAL::can ( 'Day0Ops', lc($opt) ) ){&$fref( @_ );}else{Error ("Unknown Day0Operation option: $opt @_");}}#-------------------------------------------------------------------------------# Function : Day0BuildImage## Description : Package up the created image as a tar-zip file# This allows the Image to be processed again later## Inputs : Options# --name=Name - Output Name## Returns :#sub Day0BuildImage{my $name = 'Day0Image';Message ("Create File System Image; $name");## Indicate that we have created some output#Error ("Day0Source must be specified first")unless ( $source_specified );$output_image++;## Process user options#foreach ( @_ ){if ( m~^--Name=(.+)~i ) {$name = $1;} else {Error ("Day0BuildImage: Unknown option: $_");}}## Place the file in the BIN directory# Have no reall good reason#$name = $opt_packagebindir . '/' . $name . '.tgz';CreateDir ( $opt_packagebindir);## Create a Tar command# Assumes the presence of a GNU style tar#System ( 'tar','--create','--file', $name,'--gzip',IsVerbose(1) ? ( '--verbose' ) : (),'--directory', $WORK,'.' );}#-------------------------------------------------------------------------------# Function : Day0BuildSdImage## Description : Package up the created image and create an SD memory image# This is destructive and can only be done one## Inputs : Options# --disk_blocks - Size the output disk# --full_image - Size of Full Image# --debug## Returns :#sub Day0BuildSdImage{my $debug;my %diskGeometry = (fullfs => 0, # Test Image Sizesize => 501248, # Block Size of Entire Diskrootfs => 30, # Root Size (Megabytes)logfs => 20, # Logafcfs => 150, # AFCvarfs => 'rest' # Var - has the rest);## Ensure that some work is being done#Error ("Day0Source must be specified first")unless ( $source_specified );Error ("Cannot create multiple SD images")if ( $output_sd++ );## Process user options#foreach ( @_ ){if ( m~^--disk-blocks=(\d+)$~i ) {$diskGeometry{'size'} = $1;} elsif ( m~^--full_image=(\d+)$~i ) {$diskGeometry{'fullfs'} = $1;} elsif ( m~^--rootfs=(\d+)$~i ) {$diskGeometry{'rootfs'} = $1;} elsif ( m~^--logfs=(\d+)$~i ) {$diskGeometry{'logfs'} = $1;} elsif ( m~^--afcfs=(\d+)$~i ) {$diskGeometry{'afcfs'} = $1;} elsif ( m~^--varfs=~i ) {Error ('Var File System cannot be configured');} elsif ( m~^--debug~i ) {$debug = 1;} else {Error ("Day0BuildSdImage: Unknown option: $_");}}## Perform specific processing on the image### Scan the skeleton and process .LINKS files# File links do not store well in version control systems# NOTE: .LINKS are a local invention and not a part of e2fsimage like# .DEVICES on which they are modelled.#Message ("Locate LINKFILES in $WORK");foreach my $linkfile ( Internal::FindFiles( $WORK, ".LINKS" )){my $BASEDIR = StripFileExt( $linkfile );$BASEDIR =~ s~^$WORK/~~;Message "Expand links: $BASEDIR";open (LF, "<", $linkfile ) || Error ("Cannot open link file: $linkfile" );while ( <LF> ){chomp;next if ( m~^#~ );next unless ( $_ );my ($link, $file) = split;Internal::MakeSymLink($file ,"$BASEDIR/$link", '--NoDotDot' );}close (LF);unlink $linkfile;}# Update the Shared Library Cache#Message ("Create Shared Library Cache");System ('/sbin/ldconfig', '-r', $WORK );## Make every thing executable# This is good for directories# This is good for all files. Shouldn't be an issue to files in /etc#Message ("Mark files as executable");foreach my $dir ( glob ("$WORK/*") ){next if ( $dir =~ m~/etc$~ );next if ( $dir =~ m~/linuxrc$~ );System ('chmod', '-R', 'a+rx', $dir );}foreach my $dir ( glob ("$WORK/etc/*") ){next unless ( -d $dir );System ('chmod', '-R', 'a+rx', $dir );}## Special considertaion# /etc/busybox.conf - Accessible by root# /bin/busybox - setuid#System ('chmod', '600', "$WORK/etc/busybox.conf" );System ('chmod', '4755', "$WORK/bin/busybox" );## Stop here if debugging# Don't create the actual image as the process destroys the image#Error ("Day0BuildSdImage: Debug Image. SD Image not built")if ( $debug );## Invoke SD build function# Held in another package to make this one readable#my $name = "${opt_buildname}-${opt_version}-${opt_target}";CreateSdImage( $opt_packagebindir, $name, $WORK, $BUILD, \%diskGeometry );}#-------------------------------------------------------------------------------# Function : AddInitScript## Description : Add an Init Script to the target# Optionally create start and stop links## Existing links will always be delete## Inputs : $script - Name of the init script# $start - Start Number# $stop - Stop Number# Options:# --NoCopy - Don't copy the script, just add links## Returns :#sub AddInitScript{my ( $script, $start, $stop, @opts ) = @_;Error ("Day0Source must be specified first")unless ( $source_specified );Message ("AddInitScript: $script, $start, $stop");my $tdir = "/etc/init.d/init.d";my $base = StripDir($script);unless ( grep '^--NoCopy', @opts ){::CopyFile( $script, $tdir );}## Delete any existing links#foreach my $file ( glob("$WORK/etc/init.d/*$base") ){next unless ( $file =~ m~/[KS][\d]+${base}~ );unlink $file;}my $link;if ( $start ){$link = sprintf ("/etc/init.d/S%2.2d%s", $start, $base );Internal::MakeSymLink( "$tdir/$base", $link);}if ( $stop ){$link = sprintf ("/etc/init.d/K%2.2d%s", $stop, $base );Internal::MakeSymLink( "$tdir/$base", $link);}}#-------------------------------------------------------------------------------# Function : EchoFile## Description : Echo simple text to a file## Inputs : $file - Within the output workspace# $text## Returns :#sub EchoFile{my ($file, $text) = @_;Error ("Day0Source must be specified first")unless ( $source_specified );$file = $WORK . '/' . $file;$file =~ s~//~/~;unlink $file;open (DT, ">", $file ) || Error ("Cannot create $file");print DT $text || Error ("Cannot print to $file");close DT;}#-------------------------------------------------------------------------------# Function : CopyPkgDir## Description : Copy a directory to a target dir# Source directory is within a 'package'# Does not delete the target directory, but will add files## Currently does not support# Recursion# Flattening### Inputs : $src_dir - Within a package# $dst_dir - Within the output workspace## Options:# --FilterIn=Filter Simple filter# --FilterOut=Filter Simple filter## Returns :#sub CopyPkgDir{my @filter_out;my @filter_in;my @args;Error ("Day0Source must be specified first")unless ( $source_specified );## Process options#foreach ( @_ ){if ( m/^--FilterIn=(.+)/ ) {push @filter_in, $1;} elsif ( m/^--FilterOut=(.+)/ ) {push @filter_out, $1;} elsif ( m/^-/ ) {Error("CopyPkgDir: Unknown option: $_");} else {push @args, $_;}}my ($src_dir, $dst_dir) = @args;## Calculate the destination path#$dst_dir = $WORK . '/' . $dst_dir;$dst_dir =~ s~//~/~;## Validate source dir#my $full_src_dir = "$opt_interfacedir/$src_dir";Error("CopyPkgDir: Source dir not found: $src_dir") unless ( -d $full_src_dir );## Copy as required#CopyDir ( $full_src_dir, $dst_dir,'Flatten' => 1,'NoSubDirs' => 1,'Ignore' => \@filter_out,'Match' => \@filter_in,);}#-------------------------------------------------------------------------------# Function : CopyPackage## Description : Copy in files from a package located in the interface# directory.## The source directory may be:# pkg/<platform># pkg/<product># pkg/<target>## Inputs : $section - Section to search# $file - Source Path within a package# @llist - list of softlinks# Abs or Relative to destination dir## Embedded Options:# --Dest=Dir (Default is taken from $file)# --LinkFile (Append to .LINKS file)# --Rename=Name## Returns : Path to the target file#sub CopyPackage{my $dest;my $isa_linkfile;my @args;my $dfile;my @options;Error ("Day0Source must be specified first")unless ( $source_specified );## Process and Remove options#foreach ( @_ ){if ( m/^--Dest=(.*)/ ) {$dest = $1 . '/xxx';} elsif ( m/^--LinkFile/ ) {$isa_linkfile = 1;} elsif ( m/^--Rename=(.+)/ ) {push @options, $_;} elsif ( m/^--/ ) {Error ("CopyPackage: Unknown option: $_");} else {push @args, $_;}}my ($section, $file, @llist) = @args;## Default destination is the same as the source#$dest = $file unless ( $dest );my $dest_dir = StripFileExt($dest);my $tfile = Internal::LocateFile($section, $file);Error ("CopyPackage: File not found: $file") unless $tfile;## LinkFiles are special# They get concatenated to any existing Link File#if ( $isa_linkfile ){CatFile ( $tfile, "$dest_dir/.LINKS" );}else{$dfile = CopyFile ($tfile, $dest_dir, @options );foreach my $lname ( @llist ){$lname = $dest_dir . '/' . $lname unless ( $lname =~ m ~^/~ );my $dest_file = $dest_dir . '/' . StripDir($dfile);Internal::MakeSymLink($dest_file ,$lname);}}return $dfile;}#-------------------------------------------------------------------------------# Function : CatFile## Description : Copy a file to the end of a file## Inputs : $src# $dst - Within the output workspace## Returns :#sub CatFile{my ($src, $dst) = @_;$dst = $WORK . '/' . $dst;$dst =~ s~//~/~;Verbose ("CatFile: $src, $dst");Error ("Day0Source must be specified first")unless ( $source_specified );open (SF, '<', $src) || Error ("CatFile: Cannot open $src");open (DF, '>>', $dst) || Error ("CatFile: Cannot create:$dst");while ( <SF> ){print DF $_;}close (SF);close (DF);}#-------------------------------------------------------------------------------# Function : CopyFile## Description : Copy a file to a target dir## Inputs : $src# $dst_dir - Within the output workspace# Options - Optional flags# --Symlink# Copies symlink, not symlink target# --Rename=xxx# Renames file## Returns : Full path to destination file#sub CopyFile{my ($src, $dst_dir, @opts ) = @_;my $tfile = StripDir($src);my %opts;Error ("Day0Source must be specified first")unless ( $source_specified );## Extract options#foreach ( @opts ){if ( m/^--Symlink/ ) {$opts{DuplicateLinks} = 1;} elsif ( m/^--Rename=(.+)/ ) {$tfile = $1;} else {Error("CopyFile: Unknown option: $_");}}## Calculate the destination path#$dst_dir = $WORK . '/' . $dst_dir;$dst_dir =~ s~//~/~;## Determine the full name of the target#my $dst_file = "$dst_dir/$tfile";Verbose ("CopyFile: $src, $dst_dir");return JatsCopy::CopyFile( $src, $dst_file, \%opts );}#-------------------------------------------------------------------------------# Function : AUTOLOAD## Description : Intercept bad user directives and issue a nice error message# This is a simple routine to report unknown user directives# It does not attempt to distinguish between user errors and# programming errors. It assumes that the program has been# tested. The function simply report filename and line number# of the bad directive.## Inputs : Original function arguments ( not used )## Returns : This function does not return#sub AUTOLOAD{my $fname = $::AUTOLOAD;$fname =~ s~^\w+::~~;my ($package, $filename, $line) = caller;Error ("Directive not known or not allowed in this context: $fname","Directive: $fname( @_ );","File: $filename, Line: $line" );}#-------------------------------------------------------------------------------# Function : FirstBoot## Description : Add a file to the first boot section# Assumes that the firstboot directory is /var/afc/firstboot# This is the default## Inputs : All options# --Debian=xxx[,opts] - Locate debian package# Sub opts are:# --Arch=xxx# --Product=xxx# --Debug# --Prod# --File=yyy - Locate a files# --Level=nn - Level to run (default=50)## Returns :#sub FirstBoot{my $file;my $level = 50;Error ("Day0Source must be specified first")unless ( $source_specified );## Collect user items#foreach ( @_ ){if ( m~^--Debian=(.+)~ ) {Error ("FirstBoot: Multiple source files not supported in one directive: $_") if $file;$file = Internal::LocateDebianFile($1, $opt_target, $opt_product);} elsif ( m~^--File=(.+)~ ) {Error ("FirstBoot: Multiple source files not supported in one directive: $_") if $file;$file = $1;} elsif ( m~^--Level=(\d+)~ ) {$level = $1;Error ("FirstBoot: Invalid Level: $_") if ($level < 0 || $level > 99);} else {Error ("FirstBoot: Unknown option or argument: $_");}}## Insert the required file# Prepend name with a two digit level#my $fname = sprintf ('%2.2d.%s', $level, StripDir($file) );Message ("FirstBoot: $fname");CopyFile ( $file, '/var/afc/firstboot', "--Rename=$fname" );}################################################################################################################################################################## Package to contain DayOp opereration#package Day0Ops;use strict;use warnings;use JatsError;use JatsSystem;use JatsCopy qw(SetCopyDirDefaults DeleteDir CopyDir CreateDir);#-------------------------------------------------------------------------------# Function : hostname## Description : Insert hostname information into the target# Insert /etc/devicetype# Insert into hostname too### Inputs :## Returns :#sub hostname{Message ("Insert Hostname an Devicename: ${opt_product}");::EchoFile ( "/etc/devicetype", $opt_product );::EchoFile ( "/etc/hostname", $opt_product );::EchoFile ( "/etc/day0-version", "$opt_buildname $opt_version $opt_product $opt_platform $opt_target" );}#-------------------------------------------------------------------------------# Function : setupbusybox## Description : Insert busybox into the skeleton# Locate busybox and associated links file## Inputs : None## Returns : Nothing#sub setupbusybox{## Insert busybox into the skeleton# Locate busybox and associated links file#Message ("Copy in busybox");my $bbfile = ::CopyPackage ('bin', 'busybox', "--Dest=bin" );my $bblinks = ::CopyPackage ('bin', 'busybox.links', "--Dest=bin" );## Expand the busybox links# Use soft links. Expect that they will be easier to update in the field# Keep the .links file on the target.#Message "Expand busybox links";open ( BBLINK, "<", $bblinks ) || Error ("Cannot open BusyBox Links file");while ( <BBLINK> ){s~\s+~~;Internal::MakeSymLink ("/bin/busybox", $_, '--NoDotDot' );}close BBLINK;## May want to convert busybox.links into a .LINKS file and process# it when we instantiate the file system#}#-------------------------------------------------------------------------------# Function : upgrade## Description : Insert day0 upgrade components## Inputs : None## Returns : Nothing#sub upgrade{Message ("Copy in day0 upgrade");my $DAY0BIN="/afc/day-zero/bin"; #/day-zero::CopyPackage ('bin', "--Dest=$DAY0BIN", 'udp_broadcast' );::CopyPackage ('bin', "--Dest=$DAY0BIN", 'udp_listen' );::CopyPackage ('scripts', "--Dest=$DAY0BIN", 'day-zero.conf' );::CopyPackage ('scripts', "--Dest=$DAY0BIN", 'day-zero.sh', 'day-zero' );## Start Day-Zero Service# The service script is a part of the skeleton#::AddInitScript ("day-zero" , 95, 100-95, "--NoCopy" );}#-------------------------------------------------------------------------------# Function : dams## Description : Insert DAMS# Only sutable for single exe versions## Inputs :## Returns :#sub dams{Message ("Copy in DAMS");::CopyPackage ('bin', "--Dest=/afc/dams/bin", 'dams' );}#-------------------------------------------------------------------------------# Function : wirelesstools## Description : Insert wireless tools# This is a multi-call binary# Inputs :## Returns :#sub wirelesstools{Message ("Copy in wireless tools");::CopyPackage ('bin', 'ifrename' , "--Dest=/sbin");::CopyPackage ('bin', 'iwconfig' , "--Dest=/sbin");::CopyPackage ('bin', 'iwevent' , "--Dest=/sbin");::CopyPackage ('bin', 'iwgetid' , "--Dest=/sbin");::CopyPackage ('bin', 'iwlist' , "--Dest=/sbin");::CopyPackage ('bin', 'iwpriv' , "--Dest=/sbin");::CopyPackage ('bin', 'iwspy' , "--Dest=/sbin");}#-------------------------------------------------------------------------------# Function : zd1211## Description : Copy in the zd1211 support files## Inputs :## Returns :#sub zd1211{Message ("Copy in zd1211 firmware");::CopyPkgDir ( 'pkg/zd1211', '/lib/firmware/zd1211', '--FilterOut=READ*' );## Install the start up script# This will be delivered by the kernel package#::AddInitScript ("$opt_interfacedir/etc/zd1211", 41, 100-41 );}#-------------------------------------------------------------------------------# Function : kernelmodules## Description : Insert Kernel Modules# Note: The EMU flavour does not have any kernel modules (yet)# Allow for no files to be present or copied## Inputs :## Returns :#sub kernelmodules{Message ("Copy in Kernel Modules");CopyDir ( "${opt_interfacedir}/bin", "$WORK/lib/modules",'Flatten' => 1,'Match' => [ '*.ko' ],'Log' => 1,);}#-------------------------------------------------------------------------------# Function : e2fsprogs## Description : Insert e2fsprogs# Busybox 1.4.2 and later does not provide these utilities# so they have been built up.## Inputs :## Returns :#sub e2fsprogs{## Only install the files that are needed#Message ("Copy in e2fsprogs");::CopyPackage ('pkg', "/etc/mke2fs.conf");::CopyPackage ('pkg', "/sbin/fsck");::CopyPackage ('pkg', "/sbin/tune2fs" ,"e2label" ,"findfs");::CopyPackage ('pkg', "/sbin/mke2fs" ,"mkfs.ext2" ,"mkfs.ext3");::CopyPackage ('pkg', "/sbin/e2fsck" ,"fsck.ext2" ,"fsck.ext3");#::CopyPackage ('pkg', "/sbin/badblocks");#::CopyPackage ('pkg', "/sbin/blkid");#::CopyPackage ('pkg', "/sbin/debugfs");#::CopyPackage ('pkg', "/sbin/dumpe2fs");#::CopyPackage ('pkg', "/sbin/logsave");::CopyPackage ('pkg', "/sbin/resize2fs");}#-------------------------------------------------------------------------------# Function : compilerruntime## Description : Copy in the runtime shared libraries provided by the compiler# Many libraries are also symlinked# Need to ensure that the linkis copied## Strip many ( but not all) of the libaries# Some are special# Inputs :## Returns :#sub compilerruntime{Message ("Copy in Compiler Shared Libaries");my @slibs;JatsCopy::CopyDir( $CROSSLIBS, "$WORK/lib",'Flatten' => 1,'NoSubDirs' => 1,'DuplicateLinks' => 1,'Match' => [ '*.so', '*.so.*[0-9]' ],'FileList' => \@slibs,);foreach my $file (@slibs){next if ( -d $file );next if ( -l $file );next if ( $file =~ m~libgcc_s.so$~ );next if ( $file =~ m~libc.so$~ );next if ( $file =~ m~libpthread.so$~ );next if ( $file =~ m~libthread_db.*\.so~ ); # Needs symbolsVerbose ("Creating debug data: $file");System ($CROSS_OBJCOPY, '--only-keep-debug', $file, $file . '.dbg' );Verbose ("Stripping: $file");System ($CROSS_OBJCOPY, '--strip-all', $file);Verbose ("Linking debug to stripped library: $file");System ($CROSS_OBJCOPY, '--add-gnu-debuglink=' . $file . '.dbg', $file);Verbose ("Delecting debug file: $file" . ".dbg");System ("rm", "-f", $file . '.dbg');}## Copy in ldconfig#Message ("Copy in the ldconfig utility");# ::CopyFile ( "${CROSSEXE}/sbin/ldconfig", "/sbin" );::CopyFile ( "${CROSSEXE}/sbin/ldconfig", "/sbin" ) if (${CROSSEXE} =~ m~gcc-4\.1\.1-glibc-2\.5~);::CopyFile ( "${CROSSEXE}/sys-root/sbin/ldconfig", "/sbin" ) if (${CROSSEXE} =~ m~gcc-4\.4\.3-glibc-2\.9~);# This is used for COBRA2 and VIPER2::CopyFile ( "${CROSSEXE}/sysroot/sbin/ldconfig", "/sbin" ) if (${CROSSEXE} =~ m~gcc-5\.2\.0-glibc-2\.17~);}#-------------------------------------------------------------------------------# Function : grub## Description : Install grub related files, if requested by the user## Inputs : Options# --Menu=file - Found locally# --Kernel=file - Found in Bin## Returns :#sub grub{my $menu;my $kernel;Message ("Installing Grub");## Extract options#foreach ( @_ ){if ( m~^--Menu=(.+)~ ) {$menu = $1;} elsif ( m~^--Kernel=(.+)~ ) {$kernel = $1;} else {Error ("Day0 Grub: Unknown option: $_");}}Error ("Day0 Grub: No Menu file specified") unless ( $menu );Error ("Day0 Grub: No Kernel file specified") unless ( $kernel );::CopyPackage ( 'pkg', '/boot/grub/grub'); # Not really needed::CopyPackage ( 'pkg', '/boot/grub/stage1'); # These are ..::CopyPackage ( 'pkg', '/boot/grub/stage2');::CopyPackage ( 'pkg', '/boot/grub/e2fs_stage1_5');## Copy in the user specified boot related files#::CopyFile ( $menu, '/boot/grub' );::CopyPackage ('bin', $kernel, '--Dest=/boot');}################################################################################################################################################################## Package to contain Internal functions# Functions placed here are not available to the user in the user scripts# They have been placed here simply to hide them from the user##package Internal;use strict;use warnings;use File::Find;use JatsError;use FileUtils;#-------------------------------------------------------------------------------# Function : MakeSymLink## Description : Create a symlink - with error detection## Inputs : old_file - Link Target# Path to the link target# If an ABS path is provided, the routine will# attempt to create a relative link.# new_file - Relative to the output work space# Path to where the 'link' file will be created# Options - Must be last# --NoClean - Don't play with links# --NoDotDot - Don't create symlinks with ..## Returns : Nothing#sub MakeSymLink{my $no_clean;my $no_dot;my @args;## Extract options#foreach ( @_ ){if ( m/^--NoClean/i ) {$no_clean = 1;} elsif ( m/^--NoDotDot/i ) {$no_dot = 1;} elsif ( m/^--/ ) {Error ("MakeSymLink: Unknown option: $_");} else {push @args, $_;}}my ($old_file, $new_file) = @args;my $tfile = $WORK . '/' . $new_file;$tfile =~ s~//~/~;Verbose ("Symlink $old_file -> $new_file" );## Create the directory in which the link will be placed# Remove any existing file of the same name#my $dir = StripFileExt( $tfile );mkdir $dir unless -d $dir;unlink $tfile;## Determine a good name of the link# Convert to a relative link in an attempt to prune them#my $sfile = $old_file;unless ( $no_clean ){$sfile = CalcRelPath( StripFileExt( $new_file ), $old_file );if ( $no_dot && $sfile =~ m~^../~ ){$sfile = $old_file;}}my $result = symlink $sfile, $tfile;Error ("Cannot create symlink. $old_file -> $new_file") unless ( $result );}#-------------------------------------------------------------------------------# Function : LocateFile## Description : Locate a file within the interface directory# These files will have come from an external package## Inputs : $section One of: bin, lib, pkg, scripts# Will be translated into a suitable path# $file Path to file## Returns : Full path to the file# Will return 'undef' if not found# The user must generate the error#sub LocateFile{my ($section, $file) = @_;my $base = "$opt_interfacedir/$section";unless ( -d $base ){Warning("LocateFile: Section not found: $section");return undef;}my @done;my @parts = GetBuildParts ($opt_interfacedir, $opt_platform );push @parts, '';foreach my $type ( $opt_type, '' ){foreach my $subdir ( @parts ){my $sfile = "$base/$subdir$type/$file";$sfile =~ s~//~/~g;Verbose2("LocateFile: $sfile");if ( -f $sfile ){unless ( @done ){push @done, $sfile;}}}}if ( $#done > 0){Warning ("LocateFile: Multiple instances of file found. Only first is used", @done);}return $done[0];}#-------------------------------------------------------------------------------# Function : LocateDebianFile## Description : Locate a debian file# Internal Function## Scan packages for the Debian package specified# The user provides the base name of the package# A Debian Package name has several fields# These are:# 1) Base Name - Provided by the user# 2) Version - Version will be wildcarded# 3) Architecture - Wildcarded. Uses bin/arch directory## Expect to find Debian Packages in the bin/PLATFORM subdir## Inputs : Debian base name, complete with suboptions## Returns : Full path of the file#sub LocateDebianFile{my ($arg, $arch, $product) = @_;Verbose("LocateDebianFile: Processing: $arg");my @type = qw( P D );my %debian_file_path;## Extract sub-options# --Prod[uction]# --Debug# --Arch[itecture]=yyy#my ($base_name, @opts) = split( ',', $arg );foreach ( @opts ){if ( m/^--Arch(.*)=(.+)/ ) {$arch=$2;} elsif ( m/^--Product=(.+)/ ) {$product=$1;} elsif ( m/^--Prod/ ) {@type = 'P';} elsif ( m/^--Debug/ ) {@type = 'D';}}## Create a list of products# ie: PRODUCT_ARCH#my @products;push @products, $product . '_' . $arch if ( $product );push @products, $arch;## Scan all packages for the specified debian package#foreach my $package_dir ( $opt_interfacedir ){foreach my $type ( @type ){foreach my $prd ( @products ){foreach my $joiner ( qw(/ .) ){my $dir = "$package_dir/bin$joiner$prd$type";Verbose("LocateDebianFile: Search in $dir");next unless ( -d $dir );my @files = glob ( "$dir/${base_name}_*.deb" );next unless ( @files );push @{$debian_file_path{$type}}, @files;}}}}Error ("Required Debain package not found: $base_name",) unless %debian_file_path;## Select 'preferred' type of file# If we are doing a debug build, then prefer debug package# If not available then use any available#my @debian_file_path = @{$debian_file_path{$opt_type}};if ( ! @debian_file_path ){foreach ( keys %debian_file_path ){push @debian_file_path,@{$debian_file_path{$_}};}}Error ("Multiple matching Debian Packages located", @debian_file_path)if ( $#debian_file_path > 0 );return $debian_file_path[0];}#-------------------------------------------------------------------------------# Function : CalcRelPath## Description : Return the relative path to the current working directory# as provided in $Cwd## Inputs : $Cwd - Base dir# $base - Path to convert## Returns : Relative path from the $Cwd#sub CalcRelPath{my ($Cwd, $base) = @_;my @base = split ('/', $base );my @here = split ('/', $Cwd );my $result;Debug("CalcRelPath: Source: $base");return $base unless ( $base =~ m~^/~ );## Remove common bits from the head of both lists#while ( $#base >= 0 && $#here >= 0 && $base[0] eq $here[0] ){shift @base;shift @here;}## Need to go up some directories from here and then down into base#$result = '../' x ($#here + 1);$result .= join ( '/', @base);$result = '.' unless ( $result );$result =~ s~//~/~g;$result =~ s~/$~~;Debug("CalcRelPath: Result: $result");return $result;}#-------------------------------------------------------------------------------# Function : GetBuildParts## Description : Determine the 'parts' of the build for the current platform# This is complex information. It is held within the build.cfg# file.## Inputs : $interface_dir - Path to the interface dir# $platform - Platform to process## Returns : An array of platform parts### The following varaibles are "read" in from the build.cfg file# In order to access them we need to declare them#our %ScmBuildPkgRules;our %BUILDPLATFORM_PARTS;sub GetBuildParts{my ($interface_dir, $platform) = @_;## Tthe build.cfg file is within the interface directory#my $cfgfile = "$interface_dir/build.cfg";Error ("Cannot find file: $cfgfile" ) unless ( -f $cfgfile );## Include the build.cfg data#require ( $cfgfile );## Extract the platform parts#if ( exists $BUILDPLATFORM_PARTS{$platform}){return @{$BUILDPLATFORM_PARTS{$platform}};}else{Error ("Platform not found in build.cfg: $platform");}}#-------------------------------------------------------------------------------# Function : FindFiles## Description : Locate files within a given dir tree## Inputs : $root - Base of the search# $match - Re to match## Returns : A list of files that match#my @FIND_LIST;my $FIND_NAME;sub FindFiles{my ($root, $match ) = @_;Verbose2("FindFiles: Root: $root, Match: $match");## Becareful of closure, Must use globals#@FIND_LIST = ();$FIND_NAME = $match;File::Find::find( \&find_files, $root);## Find callback program#sub find_files{my $item = $File::Find::name;return if ( -d $_ );return unless ( $_ =~ m~$FIND_NAME~ );push @FIND_LIST, $item;}return @FIND_LIST;}