summaryrefslogtreecommitdiffstats
path: root/src/boot-env/OpenSLX
diff options
context:
space:
mode:
authorSebastian Schmelzer2010-09-02 17:50:49 +0200
committerSebastian Schmelzer2010-09-02 17:50:49 +0200
commit416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5 (patch)
tree4715f7d742fec50931017f38fe6ff0a89d4ceccc /src/boot-env/OpenSLX
parentFix for the problem reported on the list (sed filter forgotten for the (diff)
downloadcore-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.tar.gz
core-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.tar.xz
core-416ab8a37f1b07dc9f6c0fb3ff1a8ff2036510b5.zip
change dir structure
Diffstat (limited to 'src/boot-env/OpenSLX')
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/Base.pm160
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/PBS.pm247
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/PXE.pm336
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/Preboot.pm209
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/Preboot/Base.pm111
-rw-r--r--src/boot-env/OpenSLX/BootEnvironment/Preboot/CD.pm155
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Base.pm48
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Debian.pm61
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Scilin.pm61
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Suse.pm62
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu.pm73
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu_9.pm38
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Engine/Base.pm453
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Engine/PBS.pm42
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Engine/Preboot.pm143
-rw-r--r--src/boot-env/OpenSLX/MakeInitRamFS/Engine/SlxBoot.pm264
16 files changed, 2463 insertions, 0 deletions
diff --git a/src/boot-env/OpenSLX/BootEnvironment/Base.pm b/src/boot-env/OpenSLX/BootEnvironment/Base.pm
new file mode 100644
index 00000000..aa4cbe5b
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/Base.pm
@@ -0,0 +1,160 @@
+# Copyright (c) 2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::Base.pm
+# - provides empty base of the BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::Base;
+
+use strict;
+use warnings;
+
+our $VERSION = 1.01; # API-version . implementation-version
+
+use Clone qw(clone);
+use File::Basename;
+use File::Path;
+
+use OpenSLX::Basics;
+use OpenSLX::ConfigDB;
+use OpenSLX::MakeInitRamFS::Engine::SlxBoot;
+use OpenSLX::Utils;
+
+our %initramfsMap;
+
+sub new
+{
+ my $class = shift;
+
+ my $self = {};
+
+ return bless $self, $class;
+}
+
+sub initialize
+{
+ my $self = shift;
+ my $params = shift;
+
+ $self->{'dry-run'} = $params->{'dry-run'};
+
+ return 1;
+}
+
+sub finalize
+{
+ my $self = shift;
+ my $delete = shift;
+
+ return 1 if $self->{'dry-run'};
+
+ my $rsyncDeleteClause = $delete ? '--delete' : '';
+ my $rsyncCmd
+ = "rsync -a $rsyncDeleteClause --delay-updates $self->{'target-path'}/ $self->{'original-path'}/";
+ slxsystem($rsyncCmd) == 0
+ or die _tr(
+ "unable to rsync files from '%s' to '%s'! (%s)",
+ $self->{'target-path'}, $self->{'original-path'}, $!
+ );
+ rmtree([$self->{'target-path'}]);
+
+ return 1;
+}
+
+sub requiresDefaultClientConfig
+{
+ my $self = shift;
+
+ return $self->{'requires-default-client-config'};
+}
+
+sub writeBootloaderMenuFor
+{
+ my $self = shift;
+ my $client = shift;
+ my $externalClientID = shift;
+ my $systemInfos = shift;
+
+ return;
+}
+
+sub writeFilesRequiredForBooting
+{
+ my $self = shift;
+ my $info = shift;
+ my $buildPath = shift;
+
+ my $kernelFile = $info->{'kernel-file'};
+ my $kernelName = basename($kernelFile);
+
+ my $vendorOSPath = "$self->{'target-path'}/$info->{'vendor-os'}->{name}";
+ mkpath $vendorOSPath unless -e $vendorOSPath || $self->{'dry-run'};
+
+ my $targetKernel = "$vendorOSPath/$kernelName";
+ if (!-e $targetKernel) {
+ vlog(1, _tr('copying kernel %s to %s', $kernelFile, $targetKernel));
+ slxsystem(qq[cp -p "$kernelFile" "$targetKernel"])
+ unless $self->{'dry-run'};
+ }
+
+ # create initramfs:
+ my $initramfsName = "$vendorOSPath/$info->{'initramfs-name'}";
+ vlog(1, _tr('generating initialramfs %s', $initramfsName));
+ $self->_makeInitRamFS($info, $initramfsName);
+ return 1;
+}
+
+sub _makeInitRamFS
+{
+ my $self = shift;
+ my $info = shift;
+ my $initramfs = shift;
+
+ my $vendorOS = $info->{'vendor-os'};
+ my $kernelFile = basename(followLink($info->{'kernel-file'}));
+
+ my $attrs = clone($info->{attrs} || {});
+
+ chomp(my $slxVersion = qx{slxversion});
+
+ my $params = {
+ 'attrs' => $attrs,
+ 'export-name' => $info->{export}->{name},
+ 'export-uri' => $info->{'export-uri'},
+ 'initramfs' => $initramfs,
+ 'kernel-params'
+ => [ split ' ', ($info->{attrs}->{kernel_params} || '') ],
+ 'kernel-version' => $kernelFile =~ m[-(.+)$] ? $1 : '',
+ 'plugins' => $info->{'active-plugins'},
+ 'root-path'
+ => "$openslxConfig{'private-path'}/stage1/$vendorOS->{name}",
+ 'slx-version' => $slxVersion,
+ 'system-name' => $info->{name},
+ };
+
+ # TODO: make debug-level an explicit attribute, it's used in many places!
+ my $kernelParams = $info->{attrs}->{kernel_params} || '';
+ if ($kernelParams =~ m{debug(?:=(\d+))?}) {
+ my $debugLevel = defined $1 ? $1 : '1';
+ $params->{'debug-level'} = $debugLevel;
+ }
+
+ my $makeInitRamFSEngine
+ = OpenSLX::MakeInitRamFS::Engine::SlxBoot->new($params);
+ $makeInitRamFSEngine->execute($self->{'dry-run'});
+
+ # copy back kernel-params, as they might have been changed (by plugins)
+ $info->{attrs}->{kernel_params}
+ = join ' ', $makeInitRamFSEngine->kernelParams();
+
+ return;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/BootEnvironment/PBS.pm b/src/boot-env/OpenSLX/BootEnvironment/PBS.pm
new file mode 100644
index 00000000..2072884b
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/PBS.pm
@@ -0,0 +1,247 @@
+# Copyright (c) 2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::Preboot.pm
+# - provides general preboot implementation of the BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::PBS;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::BootEnvironment::Base);
+
+use OpenSLX::MakeInitRamFS::Engine::PBS;
+
+use Clone qw(clone);
+use File::Basename;
+use File::Path;
+
+use Data::Dumper;
+
+use JSON;
+use HTTP::Request::Common;
+use LWP::UserAgent;
+
+use OpenSLX::Basics;
+use OpenSLX::ConfigDB qw(:support);
+use OpenSLX::Utils;
+
+sub initialize
+{
+ my $self = shift;
+ my $params = shift;
+
+ return if !$self->SUPER::initialize($params);
+
+ $self->{'original-path'} = "$openslxConfig{'public-path'}/pbs";
+ $self->{'target-path'} = "$openslxConfig{'public-path'}/pbs.new";
+
+ $self->{'requires-default-client-config'} = 0;
+ # we do not need a default.tgz since there's always an explicit client
+
+
+ if (!$self->{'dry-run'}) {
+ mkpath([$self->{'original-path'}]);
+ rmtree($self->{'target-path'});
+ mkpath("$self->{'target-path'}/client-config");
+ }
+
+ return 1;
+}
+
+sub writeBootloaderMenuFor
+{
+ my $self = shift;
+ my $client = shift;
+ my $externalClientID = shift;
+ my $systemInfos = shift || [];
+
+ my $prebootSystemInfo
+ = clone($self->_pickSystemWithNewestKernel($systemInfos));
+
+ vlog(
+ 0,
+ _tr(
+ "\nsend preboot information for client '%s' to pbs (%s)\n".
+ " (image templates provided based of %s) ...",
+ $client->{name}, $client->{attrs}->{preboot_server}, $prebootSystemInfo->{name}
+ )
+ );
+
+ $self->_createPrebootStuff($client, $prebootSystemInfo);
+
+ my $kernel = "$self->{'target-path'}/imagebase/vmlinuz";
+ my $initramfs = "$self->{'target-path'}/imagebase/initramfs";
+
+ my $kernel_md5 = qx/md5sum $kernel | awk '{print \$1}'/;
+ my $initramfs_md5 = qx/md5sum $initramfs | awk '{print \$1}'/;
+
+ my $data_json = to_json({
+ 'slxinfo' => qx/slxversion/,
+ 'kernel' => basename($prebootSystemInfo->{'kernel-file'}),
+ 'kernel_md5' => trim($kernel_md5),
+ 'initramfs_md5' => trim($initramfs_md5),
+ 'systems' => $systemInfos
+ });
+ my $ua = LWP::UserAgent->new;
+ my $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/sync', [data => $data_json]);
+
+ if ($res->is_success) {
+ my $resData = from_json($res->content);
+ if ($resData->{'getKernel'} eq 'fresh') {
+ $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/addkernel',
+ ['kernel' => basename($prebootSystemInfo->{'kernel-file'}),
+ 'kernelFile' => ["$self->{'target-path'}/imagebase/vmlinuz"],
+ 'initramfsFile' => ["$self->{'target-path'}/imagebase/initramfs"],
+ ],
+ 'Content_Type' => 'form-data'
+ );
+
+ print Dumper($res->content);
+
+ } else {
+ if ($resData->{'getKernel'} eq 'update') {
+ $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/updatekernel',
+ ['kernel' => basename($prebootSystemInfo->{'kernel-file'}),
+ 'kernelFile' => ["$self->{'target-path'}/imagebase/vmlinuz"],
+ ],
+ 'Content_Type' => 'form-data'
+ );
+
+ print Dumper($res->content);
+ } else {
+ # do nothing
+ }
+ if ($resData->{'getInitramfs'} eq 'update') {
+ $res = $ua->request(POST 'http://pbs.experimental.openslx.org/backend/system/updateinitramfs',
+ ['kernel' => basename($prebootSystemInfo->{'kernel-file'}),
+ 'initramfsFile' => ["$self->{'target-path'}/imagebase/initramfs"],
+ ],
+ 'Content_Type' => 'form-data'
+ );
+
+ print Dumper($res->content);
+ } else {
+ # do nothing
+ }
+ }
+ } else {
+ vlog(0, 'communication with pbs failed.. please check and rerun..');
+ }
+
+ return 1;
+}
+
+sub _createPrebootStuff
+{
+ my $self = shift;
+ my $client = shift;
+ my $info = shift;
+
+ my $prebootClass = instantiateClass(
+ "OpenSLX::BootEnvironment::Preboot::Base"
+ );
+
+ my $imagebase = "$self->{'target-path'}/imagebase";
+
+ $prebootClass->initialize($self);
+ $client->{attrs}->{boot_uri} = $client->{attrs}->{preboot_server};
+ mkpath("$imagebase");
+ $self->_makePBSInitRamFS($info, "$imagebase/initramfs", $client);
+
+ my $kernelFile = $info->{'kernel-file'};
+ my $kernelName = basename($kernelFile);
+ slxsystem(qq{cp -p "$kernelFile" "$imagebase/vmlinuz"})
+ unless $self->{'dry-run'};
+
+ return 1;
+}
+
+sub _pickSystemWithNewestKernel
+{
+ my $self = shift;
+ my $systemInfos = shift;
+
+ my $systemWithNewestKernel;
+ my $newestKernelFileSortKey = '';
+ foreach my $system (@$systemInfos) {
+ next unless $system->{'kernel-file'} =~ m{
+ (?:vmlinuz|x86)-(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?-(\d+(?:\.\d+)?)
+ }x;
+ my $sortKey
+ = sprintf("%02d.%02d.%02d.%02d-%2.1f", $1, $2, $3, $4||0, $5);
+ if ($newestKernelFileSortKey lt $sortKey) {
+ $systemWithNewestKernel = $system;
+ $newestKernelFileSortKey = $sortKey;
+ }
+ }
+
+ if (!defined $systemWithNewestKernel) {
+ die _tr("unable to pick a system to be used for preboot!");
+ }
+ return $systemWithNewestKernel;
+}
+
+sub _makePBSInitRamFS
+{
+ my $self = shift;
+ my $info = shift;
+ my $initramfs = shift;
+ my $client = shift;
+
+ my $vendorOS = $info->{'vendor-os'};
+ my $kernelFile = basename(followLink($info->{'kernel-file'}));
+
+ my $attrs = clone($info->{attrs} || {});
+
+ my $bootURI = $client->{attrs}->{boot_uri};
+ if (!$bootURI) {
+ die _tr("client $client->{name} needs an URI in attribute 'boot_uri' to be used for preboot!");
+ }
+
+ chomp(my $slxVersion = qx{slxversion});
+
+ my $params = {
+ 'attrs' => $attrs,
+ 'export-name' => undef,
+ 'export-uri' => undef,
+ 'initramfs' => $initramfs,
+ 'kernel-params'
+ => [ split ' ', ($info->{attrs}->{kernel_params} || '') ],
+ 'kernel-version' => $kernelFile =~ m[-(.+)$] ? $1 : '',
+ 'plugins' => '',
+ 'root-path'
+ => "$openslxConfig{'private-path'}/stage1/$vendorOS->{name}",
+ 'slx-version' => $slxVersion,
+ 'system-name' => $info->{name},
+ 'preboot-id' => $client->{name},
+ 'boot-uri' => $bootURI,
+ };
+
+ # TODO: make debug-level an explicit attribute, it's used in many places!
+ my $kernelParams = $info->{attrs}->{kernel_params} || '';
+ if ($kernelParams =~ m{debug(?:=(\d+))?}) {
+ my $debugLevel = defined $1 ? $1 : '1';
+ $params->{'debug-level'} = $debugLevel;
+ }
+
+ my $makeInitRamFSEngine
+ = OpenSLX::MakeInitRamFS::Engine::PBS->new($params);
+ $makeInitRamFSEngine->execute($self->{'dry-run'});
+
+ # copy back kernel-params, as they might have been changed (by plugins)
+ $info->{attrs}->{kernel_params}
+ = join ' ', $makeInitRamFSEngine->kernelParams();
+
+ return;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/BootEnvironment/PXE.pm b/src/boot-env/OpenSLX/BootEnvironment/PXE.pm
new file mode 100644
index 00000000..d46786d0
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/PXE.pm
@@ -0,0 +1,336 @@
+# Copyright (c) 2008..2009 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::PXE.pm
+# - provides PXE-specific implementation of the BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::PXE;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::BootEnvironment::Base);
+
+use File::Basename;
+use File::Path;
+# for sha1 passwd encryption
+use Digest::SHA1;
+use MIME::Base64;
+
+use OpenSLX::Basics;
+use OpenSLX::Utils;
+
+sub initialize
+{
+ my $self = shift;
+ my $params = shift;
+
+ return if !$self->SUPER::initialize($params);
+
+ $self->{'original-path'} = "$openslxConfig{'public-path'}/tftpboot";
+ $self->{'target-path'} = "$openslxConfig{'public-path'}/tftpboot.new";
+
+ $self->{'requires-default-client-config'} = 1;
+
+ if (!$self->{'dry-run'}) {
+ mkpath([$self->{'original-path'}]);
+ rmtree($self->{'target-path'});
+ mkpath("$self->{'target-path'}/client-config");
+ }
+
+ return 1;
+}
+
+sub writeBootloaderMenuFor
+{
+ my $self = shift;
+ my $client = shift;
+ my $externalClientID = shift;
+ my $systemInfos = shift;
+
+ $self->_prepareBootloaderConfigFolder()
+ unless $self->{preparedBootloaderConfigFolder};
+
+ my $pxePath = $self->{'target-path'};
+ my $pxeConfigPath = "$pxePath/pxelinux.cfg";
+
+ my $pxeConfig = $self->_getTemplate();
+ my $pxeFile = "$pxeConfigPath/$externalClientID";
+ my $clientAppend = $client->{attrs}->{kernel_params_client} || '';
+ my $bootURI = $client->{attrs}->{boot_uri} || '';
+ vlog(1, _tr("writing PXE-file %s", $pxeFile));
+
+ # set label for each system
+ foreach my $info (@$systemInfos) {
+ my $label = $info->{label} || '';
+ if (!length($label) || $label eq $info->{name}) {
+ if ($info->{name} =~ m{^(.+)::(.+)$}) {
+ my $system = $1;
+ my $exportType = $2;
+ $label = $system . ' ' x (40-length($system)) . $exportType;
+ } else {
+ $label = $info->{name};
+ }
+ }
+ $info->{menuLabel} = $label;
+ }
+# if kernel=*xen* then run sub _xenLabel from xen.pm
+ my $slxLabels = '';
+ foreach my $info (sort { $a->{label} cmp $b->{label} } @$systemInfos) {
+ my $vendorOSName = $info->{'vendor-os'}->{name};
+ my $kernelName = basename($info->{'kernel-file'});
+ my $append = $info->{attrs}->{kernel_params};
+ my $pxeLabel = $info->{'external-id'};
+ $pxeLabel =~ s/::/-/g;
+ my $pxePrefix = '';
+ my $tftpPrefix = '';
+ $info->{'pxe_prefix_ip'} ||= '';
+
+ # pxe_prefix_ip set and looks like a ip
+ if ($info->{'pxe_prefix_ip'} =~ m/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
+ $pxePrefix = "$info->{'pxe_prefix_ip'}::";
+ $tftpPrefix = "tftp://$info->{'pxe_prefix_ip'}"
+ if ! length($bootURI);
+ }
+
+ # set default menu entry
+ my $pxeDefault = "";
+ if (defined $openslxConfig{'pxe-default-menu-entry'}) {
+ if ($openslxConfig{'pxe-default-menu-entry'} eq
+ $info->{'external-id'})
+ {
+ $pxeDefault = "\tMENU DEFAULT\n";
+ }
+ }
+ $append .= " initrd=$pxePrefix$vendorOSName/$info->{'initramfs-name'}";
+ $append .= " file=$bootURI" if length($bootURI);
+ $append .= " file=$tftpPrefix" if length($tftpPrefix);
+ $append .= " $clientAppend";
+ $slxLabels .= "LABEL openslx-$pxeLabel\n";
+ $slxLabels .= $pxeDefault;
+ $slxLabels .= "\tMENU LABEL ^$info->{menuLabel}\n";
+ $slxLabels .= "\tKERNEL $pxePrefix$vendorOSName/$kernelName\n";
+ $slxLabels .= "\tAPPEND $append\n";
+ $slxLabels .= "\tIPAPPEND 3\n";
+# if kernel=*xen* then run sub _xenBootEntry from xen.pm
+# if (!defined $xenKernel) {...}
+ my $helpText = $info->{description} || '';
+ if (length($helpText)) {
+ # make sure that text matches the given margin
+ my $menuMargin;
+ while ($pxeConfig =~ m{^\s*MENU MARGIN (\S+?)\s*$}gims) {
+ chomp($menuMargin = $1);
+ }
+ my $margin
+ = defined $menuMargin
+ ? "$menuMargin"
+ : "0";
+ my $marginAsText = ' ' x $margin;
+
+ my $menuWidth;
+ while ($pxeConfig =~ m{^\s*MENU WIDTH (\S+?)\s*$}gims) {
+ chomp($menuWidth = $1);
+ }
+ my $width
+ = defined $menuWidth
+ ? "$menuWidth"
+ : "80";
+ $width = $width - 2* $margin + 2;
+
+ my @atomicHelpText = split(/ /, $helpText);
+ my $lineCounter = 0;
+
+ $helpText = "";
+
+ foreach my $word (@atomicHelpText){
+ if ($lineCounter + length($word) + 1 < $width) {
+ $helpText .= "$word ";
+ $lineCounter += length($word) + 1;
+ } else {
+ my $nobreak = 1;
+ while ($nobreak == 1) {
+ my $pos = index($word,"-");
+ $nobreak = 0;
+ if ($pos != -1) {
+ if ($lineCounter + $pos + 1 < $width) {
+ $helpText .= substr($word, 0, $pos+1);
+ $word = substr($word, $pos + 1, length($word));
+ $nobreak = 1;
+ }
+ }
+ }
+ $helpText .= "\n$word ";
+ $lineCounter = length($word);
+ }
+ }
+
+ $helpText =~ s{^}{$marginAsText}gms;
+ $slxLabels .= "\tTEXT HELP\n";
+ $slxLabels .= "$helpText\n";
+ $slxLabels .= "\tENDTEXT\n";
+ }
+ }
+ # now add the slx-labels (inline or appended) and write the config file
+ if (!($pxeConfig =~ s{\@\@\@SLX_LABELS\@\@\@}{$slxLabels})) {
+ $pxeConfig .= $slxLabels;
+ # fetch PXE-bottom iclude, if exists (overwrite existing definitions)
+ my $pxeBottomFile
+ = "$openslxConfig{'config-path'}/boot-env/syslinux/pxemenu-bottom";
+ if (-e $pxeBottomFile) {
+ $pxeConfig .= "\n# configuration from include $pxeBottomFile\n";
+ $pxeConfig .= slurpFile($pxeBottomFile);
+ }
+ }
+
+ # PXE uses 'cp850' (codepage 850) but our string is in utf-8, we have
+ # to convert in order to avoid showing gibberish on the client side...
+ spitFile($pxeFile, $pxeConfig, { 'io-layer' => 'encoding(cp850)' } )
+ unless $self->{'dry-run'};
+
+ return 1;
+}
+
+sub _getTemplate
+{
+ my $self = shift;
+
+ return $self->{'pxe-template'} if $self->{'pxe-template'};
+
+ my $basePath = $openslxConfig{'base-path'};
+ my $configPath = $openslxConfig{'config-path'};
+ my $pxeTheme = $openslxConfig{'syslinux-theme'};
+
+ my ($sec, $min, $hour, $day, $mon, $year) = (localtime);
+ $mon++;
+ $year += 1900;
+ my $callDate = sprintf('%04d-%02d-%02d', $year, $mon, $day);
+ my $callTime = sprintf('%02d:%02d:%02d', $hour, $min, $sec);
+
+ # generate PXE-Menu
+ my $pxeTemplate =
+ "# generated by slxconfig-demuxer (on $callDate at $callTime)\n";
+ $pxeTemplate .= "\nDEFAULT vesamenu.c32\n";
+ # include static defaults
+ $pxeTemplate .= "\n# static configuration (override with include file)\n";
+ $pxeTemplate .= "NOESCAPE 0\n";
+ $pxeTemplate .= "PROMPT 0\n";
+
+ # first check for theme
+ # let user stuff in config path win over our stuff in base path
+ my $pxeThemePath;
+ my $pxeThemeInConfig
+ = "$configPath/boot-env/syslinux/themes/${pxeTheme}";
+ my $pxeThemeInBase
+ = "$basePath/share/boot-env/syslinux/themes/${pxeTheme}";
+ if (-e "$pxeThemeInConfig/theme.conf") {
+ $pxeThemePath = $pxeThemeInConfig;
+ }
+ else {
+ if (-e "$pxeThemeInBase/theme.conf") {
+ $pxeThemePath = $pxeThemeInBase;
+ }
+ }
+ # include theme specific stuff
+ if (defined $pxeThemePath) {
+ $pxeTemplate .= "\n# theme specific configuration from $pxeThemePath\n";
+ $pxeTemplate .= slurpFile("$pxeThemePath/theme.conf");
+ }
+
+ # copy background picture if exists
+ my $pic;
+ if (defined $pxeTheme) {
+ while ($pxeTemplate =~ m{^\s*MENU BACKGROUND (\S+?)\s*$}gims) {
+ chomp($pic = $1);
+ }
+ }
+ if (defined $pic) {
+ my $pxeBackground = "$pxeThemePath/$pic";
+ if (-e $pxeBackground && !$self->{'dry-run'}) {
+ slxsystem(qq[cp "$pxeBackground" $self->{'target-path'}/]);
+ }
+ }
+
+ # include slxsettings
+ $pxeTemplate .= "\n# slxsettings configuration\n";
+ $pxeTemplate .= "TIMEOUT $openslxConfig{'pxe-timeout'}\n" || "";
+ $pxeTemplate .= "TOTALTIMEOUT $openslxConfig{'pxe-totaltimeout'}\n" || "";
+ my $sha1pass = $self->_sha1pass($openslxConfig{'pxe-passwd'});
+ $pxeTemplate .= "MENU MASTER PASSWD $sha1pass\n" || "";
+ $pxeTemplate .= "MENU TITLE $openslxConfig{'pxe-title'}\n" || "";
+
+ # fetch PXE-include, if exists (overwrite existing definitions)
+ my $pxeIncludeFile
+ = "$openslxConfig{'config-path'}/boot-env/syslinux/pxemenu-include";
+ if (-e $pxeIncludeFile) {
+ $pxeTemplate .= "\n# configuration from include $pxeIncludeFile\n";
+ $pxeTemplate .= slurpFile($pxeIncludeFile);
+ }
+
+ $pxeTemplate .= "\n# slxsystems:\n";
+ $self->{'pxe-template'} = $pxeTemplate;
+
+ return $pxeTemplate;
+}
+
+sub _prepareBootloaderConfigFolder
+{
+ my $self = shift;
+
+ my $basePath = $openslxConfig{'base-path'};
+ my $pxePath = $self->{'target-path'};
+ my $pxeConfigPath = "$pxePath/pxelinux.cfg";
+
+ if (!$self->{'dry-run'}) {
+ rmtree($pxeConfigPath);
+ mkpath($pxeConfigPath);
+
+ for my $file ('pxelinux.0', 'pxechain.com', 'vesamenu.c32',
+ 'mboot.c32', 'kernel-shutdown', 'initramfs-shutdown') {
+ if (!-e "$pxePath/$file") {
+ slxsystem(
+ qq[cp -p "$basePath/share/boot-env/syslinux/$file" $pxePath/]
+ );
+ }
+ }
+ }
+
+ $self->{preparedBootloaderConfigFolder} = 1;
+
+ return 1;
+}
+
+# from syslinux 3.73: http://syslinux.zytor.com
+sub _random_bytes
+{
+ my $self = shift;
+ my $n = shift;
+ my($v, $i);
+
+ # using perl rand because of problems with encoding(cp850) and 'bytes'
+ srand($$ ^ time);
+ $v = '';
+ for ( $i = 0 ; $i < $n ; $i++ ) {
+ $v .= ord(int(rand() * 256));
+ }
+
+ return $v;
+}
+
+sub _sha1pass
+{
+ my $self = shift;
+ my $pass = shift;
+ my $salt = shift || MIME::Base64::encode($self->_random_bytes(6), '');
+ $pass = Digest::SHA1::sha1_base64($salt, $pass);
+
+ return sprintf('$4$%s$%s$', $salt, $pass);
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/BootEnvironment/Preboot.pm b/src/boot-env/OpenSLX/BootEnvironment/Preboot.pm
new file mode 100644
index 00000000..b06de7d2
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/Preboot.pm
@@ -0,0 +1,209 @@
+# Copyright (c) 2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::Preboot.pm
+# - provides general preboot implementation of the BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::Preboot;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::BootEnvironment::Base);
+
+use Clone qw(clone);
+use File::Basename;
+use File::Path;
+
+use OpenSLX::Basics;
+use OpenSLX::ConfigDB qw(:support);
+use OpenSLX::Utils;
+
+sub initialize
+{
+ my $self = shift;
+ my $params = shift;
+
+ return if !$self->SUPER::initialize($params);
+
+ $self->{'original-path'} = "$openslxConfig{'public-path'}/preboot";
+ $self->{'target-path'} = "$openslxConfig{'public-path'}/preboot.new";
+
+ $self->{'requires-default-client-config'} = 0;
+ # we do not need a default.tgz since there's always an explicit client
+
+ if (!$self->{'dry-run'}) {
+ mkpath([$self->{'original-path'}]);
+ rmtree($self->{'target-path'});
+ mkpath("$self->{'target-path'}/client-config");
+ }
+
+ return 1;
+}
+
+sub writeBootloaderMenuFor
+{
+ my $self = shift;
+ my $client = shift;
+ my $externalClientID = shift;
+ my $systemInfos = shift || [];
+
+ $self->_prepareBootloaderConfigFolder()
+ unless $self->{preparedBootloaderConfigFolder};
+
+ my $prebootSystemInfo
+ = clone($self->_pickSystemWithNewestKernel($systemInfos));
+
+ $self->_createImages($client, $prebootSystemInfo);
+
+ my $externalClientName = externalConfigNameForClient($client);
+ my $bootloaderPath = "$self->{'target-path'}/bootloader";
+ my $bootloaderConfigPath = "$bootloaderPath/$externalClientName";
+ mkpath($bootloaderConfigPath) unless $self->{'dry-run'};
+ my $menuFile = "$bootloaderConfigPath/bootmenu.dialog";
+
+ my $clientAppend = $client->{attrs}->{kernel_params_client} || '';
+ vlog(1, _tr("writing bootmenu %s", $menuFile));
+
+ # set label for each system
+ foreach my $info (@$systemInfos) {
+ my $label = $info->{label} || '';
+ if (!length($label) || $label eq $info->{name}) {
+ $label = $info->{name};
+ }
+ $info->{label} = $label;
+ }
+ my $bootmenuEntries = '';
+ my $entryState = 'on';
+ my $counter = 1;
+ foreach my $info (sort { $a->{label} cmp $b->{label} } @$systemInfos) {
+ my $vendorOSName = $info->{'vendor-os'}->{name};
+ my $kernelName = basename($info->{'kernel-file'});
+ my $append = $info->{attrs}->{kernel_params} || '';
+ $append .= " $clientAppend";
+ $bootmenuEntries .= qq{ "$counter" "$info->{label}" };
+ $entryState = 'off';
+
+ # create a file containing the boot-configuration for this system
+ my $systemDescr = unshiftHereDoc(<<" End-of-Here");
+ label="$info->{label}"
+ kernel="$vendorOSName/$kernelName"
+ initramfs="$vendorOSName/$info->{'initramfs-name'}"
+ append="$append"
+ End-of-Here
+ my $systemFile = "$bootloaderConfigPath/$info->{name}";
+ spitFile(
+ $systemFile, $systemDescr, { 'io-layer' => 'encoding(iso8859-1)' }
+ ) unless $self->{'dry-run'};
+ slxsystem(qq{ln -sf $info->{name} $bootloaderConfigPath/$counter});
+ $counter++;
+ }
+
+ my $entryCount = @$systemInfos;
+ my $bootmenu = unshiftHereDoc(<<" End-of-Here");
+ --no-cancel --menu "OpenSLX Boot Menu" 20 65 $entryCount $bootmenuEntries
+ End-of-Here
+
+ if (!$self->{'dry-run'}) {
+ # default to iso encoding, let's see how uclibc copes with it ...
+ spitFile($menuFile, $bootmenu, { 'io-layer' => 'encoding(iso8859-1)' });
+
+ # copy the preboot script into the folder to be tared
+ my $prebootBasePath
+ = "$openslxConfig{'base-path'}/share/boot-env/preboot";
+ slxsystem(qq{cp $prebootBasePath/preboot.sh $bootloaderConfigPath/});
+ slxsystem(qq{cp -r $prebootBasePath/preboot-scripts $bootloaderConfigPath/});
+ slxsystem(qq{chmod a+x $bootloaderConfigPath/preboot.sh});
+
+ # create a tar which can/will be downloaded by prebooting clients
+ my $tarCMD
+ = qq{cd $bootloaderConfigPath; tar -czf "${bootloaderConfigPath}.env" *};
+ slxsystem($tarCMD);
+ rmtree($bootloaderConfigPath);
+ }
+
+ return 1;
+}
+
+sub _createImages
+{
+ my $self = shift;
+ my $client = shift;
+ my $info = shift;
+
+ my %mediaMap = (
+ 'cd' => 'CD',
+ );
+ my $prebootMedia = $client->{attrs}->{preboot_media} || '';
+ if (!$prebootMedia) {
+ warn _tr(
+ "no preboot-media defined for client %s, no images will be generated!",
+ $client->{name}
+ );
+ return 0;
+ }
+ foreach my $mediumName (split m{, }, $prebootMedia) {
+ my $moduleName = $mediaMap{$mediumName}
+ or die _tr(
+ "'%s' is not one of the supported preboot-medias (cd)",
+ $mediumName
+ );
+
+ my $prebootMedium = instantiateClass(
+ "OpenSLX::BootEnvironment::Preboot::$moduleName"
+ );
+ $prebootMedium->initialize($self);
+ $prebootMedium->createImage($client, $info);
+ }
+
+ return 1;
+}
+
+sub _prepareBootloaderConfigFolder
+{
+ my $self = shift;
+
+ my $bootloaderPath = "$self->{'target-path'}/bootloader";
+ if (!$self->{'dry-run'}) {
+ rmtree($bootloaderPath);
+ mkpath($bootloaderPath);
+ }
+
+ $self->{preparedBootloaderConfigFolder} = 1;
+
+ return 1;
+}
+
+sub _pickSystemWithNewestKernel
+{
+ my $self = shift;
+ my $systemInfos = shift;
+
+ my $systemWithNewestKernel;
+ my $newestKernelFileSortKey = '';
+ foreach my $system (@$systemInfos) {
+ next unless $system->{'kernel-file'} =~ m{
+ (?:vmlinuz|x86)-(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?-(\d+(?:\.\d+)?)
+ }x;
+ my $sortKey
+ = sprintf("%02d.%02d.%02d.%02d-%2.1f", $1, $2, $3, $4||0, $5);
+ if ($newestKernelFileSortKey lt $sortKey) {
+ $systemWithNewestKernel = $system;
+ $newestKernelFileSortKey = $sortKey;
+ }
+ }
+
+ if (!defined $systemWithNewestKernel) {
+ die _tr("unable to pick a system to be used for preboot!");
+ }
+ return $systemWithNewestKernel;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/BootEnvironment/Preboot/Base.pm b/src/boot-env/OpenSLX/BootEnvironment/Preboot/Base.pm
new file mode 100644
index 00000000..89f0e07e
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/Preboot/Base.pm
@@ -0,0 +1,111 @@
+# Copyright (c) 2008-2009 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::Preboot::Base.pm
+# - base of the Preboot-BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::Preboot::Base;
+
+use strict;
+use warnings;
+
+use File::Basename;
+
+use Clone qw(clone);
+
+use OpenSLX::Basics;
+use OpenSLX::MakeInitRamFS::Engine::Preboot;
+use OpenSLX::Utils;
+
+sub new
+{
+ my $class = shift;
+
+ my $self = {};
+
+ return bless $self, $class;
+}
+
+sub initialize
+{
+ my $self = shift;
+ my $params = shift;
+
+ $self->{'dry-run'} = $params->{'dry-run'};
+
+ return 1;
+}
+
+sub makePrebootInitRamFS
+{
+ my $self = shift;
+ my $info = shift;
+ my $initramfs = shift;
+ my $client = shift;
+
+ my $vendorOS = $info->{'vendor-os'};
+ my $kernelFile = basename(followLink($info->{'kernel-file'}));
+
+ my $attrs = clone($info->{attrs} || {});
+
+ my $bootURI = $client->{attrs}->{boot_uri};
+ if (!$bootURI) {
+ die _tr("client $client->{name} needs an URI in attribute 'boot_uri' to be used for preboot!");
+ }
+
+ chomp(my $slxVersion = qx{slxversion});
+
+ my $params = {
+ 'attrs' => $attrs,
+ 'export-name' => undef,
+ 'export-uri' => undef,
+ 'initramfs' => $initramfs,
+ 'kernel-params'
+ => [ split ' ', ($info->{attrs}->{kernel_params} || '') ],
+ 'kernel-version' => $kernelFile =~ m[-(.+)$] ? $1 : '',
+ 'plugins' => '',
+ 'root-path'
+ => "$openslxConfig{'private-path'}/stage1/$vendorOS->{name}",
+ 'slx-version' => $slxVersion,
+ 'system-name' => $info->{name},
+ 'preboot-id' => $client->{name},
+ 'boot-uri' => $bootURI,
+ };
+
+ # TODO: make debug-level an explicit attribute, it's used in many places!
+ my $kernelParams = $info->{attrs}->{kernel_params} || '';
+ if ($kernelParams =~ m{debug(?:=(\d+))?}) {
+ my $debugLevel = defined $1 ? $1 : '1';
+ $params->{'debug-level'} = $debugLevel;
+ }
+
+ my $makeInitRamFSEngine
+ = OpenSLX::MakeInitRamFS::Engine::Preboot->new($params);
+ $makeInitRamFSEngine->execute($self->{'dry-run'});
+
+ # copy back kernel-params, as they might have been changed (by plugins)
+ $info->{attrs}->{kernel_params}
+ = join ' ', $makeInitRamFSEngine->kernelParams();
+
+ return;
+}
+
+sub createImage
+{
+ my $self = shift;
+ my $client = shift;
+ my $info = shift;
+
+ # override in subclasses!
+
+ return 1;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/BootEnvironment/Preboot/CD.pm b/src/boot-env/OpenSLX/BootEnvironment/Preboot/CD.pm
new file mode 100644
index 00000000..a6c36cd7
--- /dev/null
+++ b/src/boot-env/OpenSLX/BootEnvironment/Preboot/CD.pm
@@ -0,0 +1,155 @@
+# Copyright (c) 2008-2009 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# BootEnvironment::Preboot::CD.pm
+# - provides CD-specific implementation of the Preboot-BootEnvironment API.
+# -----------------------------------------------------------------------------
+package OpenSLX::BootEnvironment::Preboot::CD;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::BootEnvironment::Preboot::Base);
+
+use File::Basename;
+use File::Path;
+
+use OpenSLX::Basics;
+use OpenSLX::Utils;
+
+sub createImage
+{
+ my $self = shift;
+ my $client = shift;
+ my $info = shift;
+
+ vlog(
+ 0,
+ _tr(
+ "\ncreating CD-image for client %s (based on %s) ...",
+ $client->{name}, $info->{name}
+ )
+ );
+
+ my $imageDir = "$openslxConfig{'public-path'}/images/$client->{name}/cd";
+ my $isoDir = "$imageDir/iso/isolinux";
+ mkpath($isoDir) unless $self->{'dry-run'};
+
+ # copy static data
+ my $dataDir = "$openslxConfig{'base-path'}/share/boot-env/syslinux";
+ for my $file ('LICENSE', 'README.iso', 'vesamenu.c32', 'isolinux.bin') {
+ if (!-e "$isoDir/$file") {
+ slxsystem(
+ qq[cp -p "$dataDir/$file" "$isoDir/"]
+ )
+ unless $self->{'dry-run'};
+ }
+ }
+
+ # copy kernel (take the one from the given system info)
+ my $kernelFile = $info->{'kernel-file'};
+ my $kernelName = basename($kernelFile);
+ slxsystem(qq{cp -p "$kernelFile" "$isoDir/vmlinuz"})
+ unless $self->{'dry-run'};
+
+ # create initramfs
+ my $initramfsName = qq{"$isoDir/initramfs"};
+ $self->makePrebootInitRamFS($info, $initramfsName, $client);
+
+ # write trivial isolinux config
+ # include static defaults
+ my $isolinuxConfig = "DEFAULT vesamenu.c32\n";
+ $isolinuxConfig .= "PROMPT 0\n";
+ $isolinuxConfig .= "TIMEOUT 100\n";
+
+ # theme stuff
+ my $basePath = $openslxConfig{'base-path'};
+ my $configPath = $openslxConfig{'config-path'};
+ my $isoTheme = $openslxConfig{'syslinux-theme'};
+
+ my $isoThemePath;
+ my $isoThemeInConfig
+ = "$configPath/boot-env/syslinux/themes/${isoTheme}";
+ my $isoThemeInBase
+ = "$basePath/share/boot-env/syslinux/themes/${isoTheme}";
+ if (-e "$isoThemeInConfig/theme.conf") {
+ $isoThemePath = $isoThemeInConfig;
+ }
+ else {
+ if (-e "$isoThemeInBase/theme.conf") {
+ $isoThemePath = $isoThemeInBase;
+ }
+ }
+ # include theme specific stuff
+ if (defined $isoThemePath) {
+ $isolinuxConfig .= slurpFile("$isoThemePath/theme.conf");
+ }
+
+ # copy background picture if exists
+ my $pic;
+ if (defined $isoTheme) {
+ while ($isolinuxConfig =~ m{^\s*MENU BACKGROUND (\S+?)\s*$}gims) {
+ chomp($pic = $1);
+ }
+ }
+ if (defined $pic) {
+ my $isoBackground = "$isoThemePath/$pic";
+ if (-e $isoBackground && !$self->{'dry-run'}) {
+ slxsystem(qq[cp "$isoBackground" "$isoDir/"]);
+ }
+ }
+
+ # write trivial isolinux config
+ $isolinuxConfig .= unshiftHereDoc(<<" End-of-Here");
+ MENU TITLE Welcome to OpenSLX PreBoot ISO/CD (Mini Linux/Kexec)
+ LABEL SLXSTDBOOT
+ MENU LABEL OpenSLX PreBoot - Stateless Netboot Linux ...
+ MENU DEFAULT
+ KERNEL vmlinuz
+ APPEND initrd=initramfs vga=0x317
+ TEXT HELP
+ Use this (default) entry if you have configured your client.
+ You have chance to edit the kernel commandline by hitting
+ the TAB key (e.g. for adding debug=3 to it for bug hunting).
+ ENDTEXT
+ LABEL LOCALBOOT
+ MENU LABEL Boot locally (skip OpenSLX PreBoot) ...
+ LOCALBOOT -1
+ TEXT HELP
+ Gets you out of here by booting from next device in BIOS
+ boot order.
+ ENDTEXT
+ End-of-Here
+ spitFile("$isoDir/isolinux.cfg", $isolinuxConfig);
+
+ my $mkisoCmd = unshiftHereDoc(<<" End-of-Here");
+ mkisofs
+ -o "$imageDir/../$client->{name}.iso"
+ -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4
+ -r -J -l -boot-info-table -joliet-long
+ -publisher "OpenSLX Project - http://www.openslx.org"
+ -p "OpenSLX Project - openslx-devel\@openslx.org"
+ -V "OpenSLX BootISO"
+ -volset "OpenSLX Project - PreBoot ISO/CD for non PXE/TFTP start of a Linux Stateless Client"
+ -c isolinux/boot.cat "$imageDir/iso"
+ End-of-Here
+ $mkisoCmd =~ s{\n\s*}{ }gms;
+ my $logFile = "$imageDir/../$client->{name}.iso.log";
+ if (slxsystem(qq{$mkisoCmd 2>"$logFile"})) {
+ my $log = slurpFile($logFile);
+ die _tr("unable to create ISO-image - log follows:\n%s", $log);
+ }
+
+ rmtree($imageDir);
+
+ return 1;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Base.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Base.pm
new file mode 100644
index 00000000..9be218e8
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Base.pm
@@ -0,0 +1,48 @@
+# Copyright (c) 2006, 2007 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::Base.pm
+# - provides empty base of the distro-specific part of the OpenSLX
+# MakeInitRamFS API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Base;
+
+use strict;
+use warnings;
+
+our $VERSION = 1.01; # API-version . implementation-version
+
+use OpenSLX::Basics;
+
+################################################################################
+### interface methods
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $self = {
+ 'base-name' => 'base',
+ };
+ return bless $self, $class;
+}
+
+sub applyChanges
+{
+}
+
+sub determineMatchingHwinfoVersion
+{
+ my $self = shift;
+ my $distroVersion = shift;
+
+ return '15.3';
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Debian.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Debian.pm
new file mode 100644
index 00000000..7174474d
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Debian.pm
@@ -0,0 +1,61 @@
+# Copyright (c) 2006..2010 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::Debian.pm
+# - provides Debian-specific overrides of the MakeInitRamFS::Distro API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Debian;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Distro::Base);
+
+use OpenSLX::Basics;
+
+################################################################################
+### implementation
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $self = {
+ 'base-name' => 'debian',
+ };
+ return bless $self, $class;
+}
+
+sub applyChanges
+{
+ my $self = shift;
+ my $engine = shift;
+
+ $engine->_addFilteredKernelModules( qw( af_packet hid hid-bright unix ));
+
+ return;
+}
+
+sub determineMatchingHwinfoVersion
+{
+ my $self = shift;
+ my $distroVersion = shift;
+
+ # to be checked
+ my %versionMap = (
+ '3.0' => '13.11',
+ '4.0' => '14.19',
+ '5.0' => '15.3',
+ '6.0' => '16.0',
+ );
+ return $versionMap{$distroVersion}
+ || $self->SUPER::determineMatchingHwinfoVersion($distroVersion);
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Scilin.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Scilin.pm
new file mode 100644
index 00000000..f2372f8f
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Scilin.pm
@@ -0,0 +1,61 @@
+# Copyright (c) 2009..2010 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::Scilin.pm
+# - provides Scientific Linux specific overrides of the
+# MakeInitRamFS::Distro API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Scilin;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Distro::Base);
+
+use OpenSLX::Basics;
+
+################################################################################
+### implementation
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $self = {
+ 'base-name' => 'scilin',
+ };
+ return bless $self, $class;
+}
+
+sub applyChanges
+{
+ my $self = shift;
+ my $engine = shift;
+ # filter modules which are part of the main kernel already
+ $engine->_addFilteredKernelModules( qw( af_packet hid hid-bright usbhid unix vesafb fbcon ));
+
+ return;
+}
+
+sub determineMatchingHwinfoVersion
+{
+ my $self = shift;
+ my $distroVersion = shift;
+
+ my %versionMap = (
+ '4.7' => '13.11',
+ '5.3' => '15.3',
+ '5.4' => '15.21',
+ '5.5' => '16.0',
+ );
+ return $versionMap{$distroVersion}
+ || $self->SUPER::determineMatchingHwinfoVersion($distroVersion);
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Suse.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Suse.pm
new file mode 100644
index 00000000..cb106924
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Suse.pm
@@ -0,0 +1,62 @@
+# Copyright (c) 2006..2010 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::SUSE.pm
+# - provides SUSE-specific overrides of the MakeInitRamFS::Distro API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Suse;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Distro::Base);
+
+use OpenSLX::Basics;
+
+################################################################################
+### implementation
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $self = {
+ 'base-name' => 'suse',
+ };
+ return bless $self, $class;
+}
+
+sub applyChanges
+{
+ my $self = shift;
+ my $engine = shift;
+
+ $engine->_addFilteredKernelModules( qw( hid hid-bright unix vesafb fbcon ));
+
+ return;
+}
+
+sub determineMatchingHwinfoVersion
+{
+ my $self = shift;
+ my $distroVersion = shift;
+
+ my %versionMap = (
+ '10.2' => '13.11',
+ '10.3' => '14.19',
+ '11.0' => '15.3',
+ '11.1' => '15.21',
+ '11.2' => '16.0',
+ '11.3' => '16.0'
+ );
+ return $versionMap{$distroVersion}
+ || $self->SUPER::determineMatchingHwinfoVersion($distroVersion);
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu.pm
new file mode 100644
index 00000000..2c59bbae
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu.pm
@@ -0,0 +1,73 @@
+ # Copyright (c) 2006..2010 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::Ubuntu.pm
+# - provides Ubuntu-specific overrides of the MakeInitRamFS::Distro API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Ubuntu;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Distro::Base);
+
+use OpenSLX::Basics;
+
+################################################################################
+### implementation
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $self = {
+ 'base-name' => 'ubuntu',
+ };
+ return bless $self, $class;
+}
+
+# filter out modules not present (e.g. because compiled into the kernel)
+sub applyChanges
+{
+ my $self = shift;
+ my $engine = shift;
+
+ #if ($engine->{'distro-name'} =~ m{-([^-]+)$}) {
+ # my $distroVersion = 0.0 + $1;
+ # if ($distroVersion <= 8.10) {
+ # $engine->_addFilteredKernelModules( qw( unix hid-bright ));
+ # }
+ # else {
+ # $engine->_addFilteredKernelModules( qw( unix hid-bright af_packet uhci-hcd ohci-hcd ));
+ # }
+ #}
+ $engine->_addFilteredKernelModules( qw( unix hid-bright af_packet uhci-hcd ohci-hcd ));
+
+ return;
+}
+
+sub determineMatchingHwinfoVersion
+{
+ my $self = shift;
+ my $distroVersion = shift;
+
+ # Please check, if correct
+ my %versionMap = (
+ '7.10' => '14.19',
+ '8.04' => '15.3',
+ '8.10' => '15.21',
+ '9.04' => '15.21',
+ '9.10' => '16.0',
+ '10.04' => '16.0',
+ );
+ return $versionMap{$distroVersion}
+ || $self->SUPER::determineMatchingHwinfoVersion($distroVersion);
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu_9.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu_9.pm
new file mode 100644
index 00000000..b0087253
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Distro/Ubuntu_9.pm
@@ -0,0 +1,38 @@
+# Copyright (c) 2009 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitRamFS::Distro::Ubuntu_9.pm
+# - provides Ubuntu-9.X-specific overrides of the MakeInitRamFS::Distro API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Distro::Ubuntu_9;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Distro::Ubuntu);
+
+use OpenSLX::Basics;
+
+################################################################################
+### implementation
+################################################################################
+sub applyChanges
+{
+ my $self = shift;
+ my $engine = shift;
+
+ $engine->_addFilteredKernelModules(
+ qw( af_packet unix hid uhci-hcd ohci-hcd )
+ );
+
+ return;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Base.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Base.pm
new file mode 100644
index 00000000..b09543dc
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Base.pm
@@ -0,0 +1,453 @@
+# Copyright (c) 2006..2010 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitialRamFS::Engine::Base.pm
+# - provides basic driver engine for MakeInitialRamFS API.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Engine::Base;
+
+use strict;
+use warnings;
+use Switch;
+
+use File::Basename;
+use POSIX qw(strftime);
+
+use OpenSLX::Basics;
+use OpenSLX::LibScanner;
+use OpenSLX::OSPlugin::Roster;
+use OpenSLX::Utils;
+
+################################################################################
+### interface methods
+################################################################################
+sub new
+{
+ my $class = shift;
+ my $params = shift || {};
+
+ checkParams($params, {
+ 'attrs' => '!',
+ 'debug-level' => '?',
+ 'export-name' => '!',
+ 'export-uri' => '!',
+ 'initramfs' => '!',
+ 'kernel-params' => '!',
+ 'kernel-version' => '!',
+ 'plugins' => '!',
+ 'root-path' => '!',
+ 'slx-version' => '!',
+ 'system-name' => '!',
+ 'preboot-id' => '?',
+ 'boot-uri' => '?',
+ } );
+
+ my $self = $params;
+
+ $self->{'system-name'} =~ m{^([^\-]+)-([^:\-]+)}
+ or die "unable to extract distro-info from $self->{'system-name'}!";
+
+ $self->{'distro-name'} = lc($1);
+ $self->{'distro-ver'} = $2;
+
+ my $fullDistroName = lc($1) . '-' . $2;
+
+ $self->{distro} = loadDistroModule({
+ distroName => $fullDistroName,
+ distroScope => 'OpenSLX::MakeInitRamFS::Distro',
+ });
+ if (!$self->{distro}) {
+ die _tr(
+ 'unable to load any MakeInitRamFS::Distro module for system %s!',
+ $self->{'system-name'}
+ );
+ }
+
+ $self->{'lib-scanner'}
+ = OpenSLX::LibScanner->new({ 'root-path' => $self->{'root-path'} });
+
+ $self->{'suggested-kernel-modules'} = [];
+ $self->{'filtered-kernel-modules'} = [];
+
+ return bless $self, $class;
+}
+
+sub execute
+{
+ my $self = shift;
+ my $dryRun = shift;
+
+ $self->_collectCMDs();
+
+ vlog(1, _tr("creating initramfs '%s' ...", $self->{'initramfs'}));
+ $self->_executeCMDs() unless $dryRun;
+
+ return;
+}
+
+sub haveKernelParam
+{
+ my $self = shift;
+ my $param = shift;
+
+ return ref $param eq 'Regexp'
+ ? grep { $_ =~ $param } @{ $self->{'kernel-params'} }
+ : grep { $_ eq $param } @{ $self->{'kernel-params'} };
+}
+
+sub addKernelParams
+{
+ my $self = shift;
+
+ push @{ $self->{'kernel-params'} }, @_;
+
+ return;
+}
+
+sub kernelParams
+{
+ my $self = shift;
+
+ return @{ $self->{'kernel-params'} };
+}
+
+sub addKernelModules
+{
+ my $self = shift;
+
+ push @{ $self->{'suggested-kernel-modules'} }, @_;
+
+ return;
+}
+
+################################################################################
+### implementation methods
+################################################################################
+sub _executeCMDs
+{
+ my $self = shift;
+
+ foreach my $cmd (@{$self->{CMDs}}) {
+ if (ref($cmd) eq 'HASH') {
+ vlog(3, "writing $cmd->{file}");
+ my $flags = defined $cmd->{mode} ? { mode => $cmd->{mode} } : undef;
+ spitFile($cmd->{file}, $cmd->{content}, $flags);
+ }
+ else {
+ vlog(3, "executing: $cmd");
+ if (slxsystem($cmd)) {
+ die _tr(
+ "unable to execute shell-cmd\n\t%s", $cmd
+ );
+ }
+ }
+ }
+
+ return;
+}
+
+sub addCMD
+{
+ my $self = shift;
+ my $cmd = shift;
+
+ push @{$self->{CMDs}}, $cmd;
+
+ return;
+}
+
+sub _findBinary
+{
+ my $self = shift;
+ my $binary = shift;
+
+ my @binDirs = qw(
+ bin sbin usr/bin usr/sbin usr/local/bin usr/local/sbin usr/bin/X11
+ );
+ foreach my $binDir (@binDirs) {
+ my $binPath = "$self->{'root-path'}/$binDir/$binary";
+ return $binPath if -f $binPath && -x $binPath;
+ }
+
+ return;
+}
+
+sub _addFilteredKernelModules
+{
+ my $self = shift;
+
+ push @{ $self->{'filtered-kernel-modules'} }, @_;
+
+ return;
+}
+
+sub _copyKernelModules
+{
+ my $self = shift;
+
+ # read modules.dep and use it to determine module dependencies
+ my $sourcePath = "$self->{'root-path'}/lib/modules/$self->{'kernel-version'}";
+ my @modulesDep = slurpFile("$sourcePath/modules.dep")
+ or die _tr('unable to open %s!', "$sourcePath/modules.dep");
+ my (%dependentModules, %modulePath, %modulesToBeCopied);
+ foreach my $modulesDep (@modulesDep) {
+ next if $modulesDep !~ m{^(.+?)/([^/]+)\.ko:\s*(.*?)\s*$};
+ my $path = $1;
+ if (substr($path, 0, 5) ne '/lib/') {
+ # some distros (e.g. ubuntu-9) use a local path instead of an
+ # absolute path, we need to make it absolute:
+ $path = "/lib/modules/$self->{'kernel-version'}/$path";
+ }
+ my $module = $2;
+ my $dependentsList = $3;
+ my $fullModulePath = "$path/$module.ko";
+ $modulePath{$module} = [] if !exists $modulePath{$module};
+ push @{$modulePath{$module}}, $fullModulePath;
+ $dependentModules{$fullModulePath} = [
+ map {
+ if (substr($_, 0, 5) ne '/lib/') {
+ # some distros (e.g. ubuntu-9) use a local path instead of an
+ # absolute path, we need to make it absolute:
+ $_ = "/lib/modules/$self->{'kernel-version'}/$_";
+ }
+ $_;
+ }
+ split ' ', $dependentsList
+ ];
+ }
+
+ my $targetPath
+ = "$self->{'build-path'}/lib/modules/$self->{'kernel-version'}";
+ $self->addCMD("mkdir -p $targetPath");
+ $self->addCMD("cp -p $sourcePath/modules.* $targetPath/");
+
+ # add a couple of kernel modules that we expect to be used in stage3
+ # (some of these modules do not exist on all distros, so they will be
+ # filtered out again by the respective distro object):
+ my @kernelModules = qw(
+ af_packet unix hid hid-bright usbhid uhci-hcd ohci-hcd vesafb fbcon
+ );
+ push @kernelModules, @{ $self->{'suggested-kernel-modules'} };
+
+ push @kernelModules, split ' ', $self->{attrs}->{ramfs_fsmods};
+ push @kernelModules, split ' ', $self->{attrs}->{ramfs_miscmods};
+ push @kernelModules, split ' ', $self->{attrs}->{ramfs_nicmods};
+
+ if ($self->{attrs}->{ramfs_nicmods} =~ m{virtio}i) {
+ push @kernelModules, qw( virtio_pci virtio_net );
+ }
+
+ # a function that determines dependent modules recursively
+ my $addDependentsSub;
+ $addDependentsSub = sub {
+ my $modulePath = shift;
+ foreach my $dependentModule (@{$dependentModules{$modulePath}}) {
+ next if $modulesToBeCopied{$dependentModule};
+ $modulesToBeCopied{$dependentModule} = 1;
+ $addDependentsSub->($dependentModule);
+ }
+ };
+
+ # start with the given kernel modules (names) and build a list of all
+ # required modules
+ foreach my $kernelModule (@kernelModules) {
+ if (!$modulePath{$kernelModule}) {
+ if (! grep { $_ eq $kernelModule }
+ @{ $self->{'filtered-kernel-modules'} }
+ ) {
+ warn _tr(
+ 'kernel module "%s" not found (in modules.dep)',
+ $kernelModule
+ );
+ }
+ }
+ foreach my $modulePath (@{$modulePath{$kernelModule}}) {
+ next if $modulesToBeCopied{$modulePath};
+ $modulesToBeCopied{$modulePath} = 1;
+ $addDependentsSub->($modulePath);
+ }
+ }
+
+ # build a list of required firmwares out of the list of modules - not
+ # totally optimal
+ my @firmwares;
+ $self->addCMD("mkdir -p $self->{'build-path'}/lib/firmware/$self->{'kernel-version'}");
+ foreach my $moduleToBeCopied(%modulesToBeCopied) {
+ $moduleToBeCopied =~ /.*\/(.*?)$/;
+ # implies usage of switch
+ vlog(1,$1);
+ switch ($1){
+ case "e100.ko" {push @firmwares, split ' ', "e100"}
+ case "iwlwifi" {
+ push @firmwares, split ' ',
+ "iwlwifi-3945-1.ucode iwlwifi-3945-2.ucode iwlwifi-4965-1.ucode iwlwifi-4965-2.ucode iwlwifi-5000-1.ucode"
+ }
+ case "tg3.ko" {push @firmwares, split ' ', "tigon/"}
+ # modules required for graphic adaptors (bootsplash, Xorg)
+ case "radeon.ko" {push @firmwares, split ' ', "radeon/"}
+ case "mga.ko" {push @firmwares, split ' ', "matrox/"}
+ case "r128.ko" {push @firmwares, split ' ', "r128/"}
+ }
+ }
+ # copy all the firmwares that we think are required
+ foreach my $firmwareToBeCopied (@firmwares) {
+ my $source = followLink(
+ "$self->{'root-path'}/lib/firmware/$self->{'kernel-version'}/$firmwareToBeCopied", $self->{'root-path'}
+ );
+ if (-e $source){
+ my $target = "$self->{'build-path'}/lib/firmware/";
+
+ $self->addCMD("cp -pr --dereference $source $target");
+ } else {
+ vlog(3,"unable to find $source for copying purposes");
+ }
+ }
+
+ # copy all the modules that we think are required
+ foreach my $moduleToBeCopied (sort keys %modulesToBeCopied) {
+ my $source = followLink(
+ "$self->{'root-path'}$moduleToBeCopied", $self->{'root-path'}
+ );
+ my $target = "$self->{'build-path'}$moduleToBeCopied";
+ my ($targetdir) = $target =~m/(.*\/).*$/;
+ vlog(5,"Trying to make directory: $targetdir");
+ $self->addCMD("mkdir -p $targetdir");
+ $self->addCMD("cp -p --dereference $source $target");
+ }
+
+ return;
+}
+
+sub _platformSpecificFileFor
+{
+ my $self = shift;
+ my $binary = shift;
+
+ if ($self->{'system-name'} =~ m{64}) {
+ return $binary . '.x86_64';
+ }
+ return $binary . '.i586';
+}
+
+sub _writeInitramfsSetup
+{
+ my $self = shift;
+
+ # generate initramfs-setup file containing attributes that are
+ # relevant for the initramfs only (before there's a root-FS):
+ my $initramfsAttrs = {
+ 'host_name' => 'slx-client', # just to have something at all
+ 'ramfs_fsmods' => $self->{attrs}->{ramfs_fsmods} || '',
+ 'ramfs_miscmods' => $self->{attrs}->{ramfs_miscmods} || '',
+ 'ramfs_nicmods' => $self->{attrs}->{ramfs_nicmods} || '',
+ 'ramfs_firmmods' => $self->{attrs}->{ramfs_firmmods} || '',
+ 'rootfs' => $self->{'export-uri'} || '',
+ 'hw_local_disk' => $self->{attrs}->{hw_local_disk} || '',
+ };
+ my $content = "# attributes set by slxconfig-demuxer:\n";
+ foreach my $attr (keys %$initramfsAttrs) {
+ $content .= qq[$attr="$initramfsAttrs->{$attr}"\n];
+ }
+ $self->addCMD( {
+ file => "$self->{'build-path'}/etc/initramfs-setup",
+ content => $content
+ } );
+
+ return;
+}
+
+sub _writeSlxSystemConf
+{
+ my $self = shift;
+
+ # generate slxsystem.conf file with variables that are needed
+ # in stage3 init.
+ # TODO: either put this stuff into initramfs-setup or find another solution
+ my $date = strftime("%d.%m.%Y", localtime);
+ my $slxConf = unshiftHereDoc(<<" End-of-Here");
+ slxconf_date=$date
+ slxconf_kernver=$self->{'kernel-version'}
+ slxconf_listnwmod="$self->{attrs}->{ramfs_nicmods}"
+ slxconf_distro_name=$self->{'distro-name'}
+ slxconf_distro_ver=$self->{'distro-ver'}
+ slxconf_system_name=$self->{'system-name'}
+ slxconf_slxver="$self->{'slx-version'}"
+ End-of-Here
+ $self->addCMD( {
+ file => "$self->{'build-path'}/etc/slxsystem.conf",
+ content => $slxConf
+ } );
+
+ # check if default directories available and copy them to /etc
+ my $defaultDirConfig = "$self->{'root-path'}/etc/opt/openslx/openslx.conf";
+ my $configTargetPath = "$self->{'build-path'}/etc";
+ #my $defaultConfVer = slurpFile("$defaultDirConfig");
+ #my $actConfVer = "Version 0.2";
+
+ if (-r $defaultDirConfig) {
+ $self->addCMD("cp -p $defaultDirConfig $configTargetPath/");
+# if ($defaultConfVer =~ m{$actConfVer}) {
+# warn _tr(
+# "Your version of default dir file (openslx.conf) is to old!\n".
+# "Eventually the system won't work.\n" .
+# "Please run install, update or clone of this system again!\n");
+# }
+ } else {
+ die _tr(
+ "No default directories defined!\n" .
+ "Please run install, update or clone of this system again!\n");
+ }
+
+ return;
+}
+
+sub _calloutToPlugins
+{
+ my $self = shift;
+
+ my $pluginInitdPath = "$self->{'build-path'}/etc/plugin-init.d";
+ my $initHooksPath = "$self->{'build-path'}/etc/init-hooks";
+ $self->addCMD("mkdir -p $pluginInitdPath $initHooksPath");
+
+ foreach my $pluginName (@{$self->{'plugins'}}) {
+ my $plugin = OpenSLX::OSPlugin::Roster->getPlugin($pluginName);
+ next if !$plugin;
+
+ # create a hash only containing the attributes relating to the
+ # current plugin
+ my $allAttrs = $self->{attrs};
+ my %pluginAttrs;
+ for my $attrName (grep { $_ =~ m{^${pluginName}::} } keys %$allAttrs) {
+ $pluginAttrs{$attrName} = $allAttrs->{$attrName};
+ }
+
+ # let plugin setup itself in the initramfs
+ $plugin->setupPluginInInitramfs(\%pluginAttrs, $self);
+ }
+ return;
+}
+
+sub _createInitRamFS
+{
+ my $self = shift;
+
+ my $buildPath = $self->{'build-path'};
+ $self->addCMD("chroot $buildPath ldconfig");
+ $self->addCMD(
+ "cd $buildPath "
+ . "&& find . "
+ . "| cpio -H newc --quiet --create "
+ . "| gzip -9 >$self->{initramfs}"
+ );
+
+ return;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Engine/PBS.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/PBS.pm
new file mode 100644
index 00000000..571057ad
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/PBS.pm
@@ -0,0 +1,42 @@
+# Copyright (c) 2009 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitialRamFS::Engine::PBS.pm
+# - provides driver engine for MakeInitialRamFS API, implementing the
+# base of all preboot variants.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Engine::PBS;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Engine::Preboot);
+
+use OpenSLX::Basics;
+use OpenSLX::Utils;
+
+sub _copyPrebootSpecificFiles
+{
+ my $self = shift;
+
+ # write secondary rootfs-layer (including init) on top of base layer
+ my $prebootRootfs
+ = "$openslxConfig{'base-path'}/share/boot-env/preboot/uclib-rootfs";
+ $self->addCMD("rsync -rlpt $prebootRootfs/ $self->{'build-path'}");
+
+ # overwrite preboot defaults
+ my $pbsRootfs
+ = "$openslxConfig{'base-path'}/share/boot-env/pbs/uclib-rootfs";
+ $self->addCMD("rsync -rlpt $pbsRootfs/ $self->{'build-path'}");
+
+ return 1;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Preboot.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Preboot.pm
new file mode 100644
index 00000000..aecfd00f
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/Preboot.pm
@@ -0,0 +1,143 @@
+# Copyright (c) 2006-2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitialRamFS::Engine::Preboot.pm
+# - provides driver engine for MakeInitialRamFS API, implementing the
+# base of all preboot variants.
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Engine::Preboot;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Engine::Base);
+
+use OpenSLX::Basics;
+use OpenSLX::Utils;
+
+################################################################################
+### implementation methods
+################################################################################
+sub _collectCMDs
+{
+ my $self = shift;
+
+ $self->{CMDs} = [];
+
+ $self->_setupBuildPath();
+
+ $self->_writeInitramfsSetup();
+ $self->_writeSlxSystemConf();
+
+ $self->_copyUclibcRootfs();
+ $self->_copyPrebootSpecificFiles();
+
+ $self->{distro}->applyChanges($self);
+
+ $self->_copyKernelModules();
+
+ $self->_createInitRamFS();
+
+ return;
+}
+
+sub _setupBuildPath
+{
+ my $self = shift;
+
+ my $buildPath = "$openslxConfig{'temp-path'}/slx-initramfs";
+ $self->addCMD("rm -rf $buildPath");
+
+ my @stdFolders = qw(
+ bin
+ dev
+ etc
+ lib
+ mnt
+ proc
+ root
+ sbin
+ sys
+ tmp
+ var/lib
+ var/run
+ );
+ $self->addCMD(
+ 'mkdir -p ' . join(' ', map { "$buildPath/$_"; } @stdFolders)
+ );
+
+ $self->{'build-path'} = $buildPath;
+
+ return;
+}
+
+sub _writeInitramfsSetup
+{
+ my $self = shift;
+
+ # generate initramfs-setup file containing attributes that are
+ # relevant for the initramfs only (before there's a root-FS) -
+ # this override adds the name of the client such that the booting
+ # system has an ID to use for accessing the corresponding boot environment
+ # on the server
+ my $initramfsAttrs = {
+ 'host_name' => 'slx-client', # just to have something at all
+ 'ramfs_miscmods' => $self->{attrs}->{ramfs_miscmods} || '',
+ 'ramfs_nicmods' => $self->{attrs}->{ramfs_nicmods} || '',
+ 'ramfs_firmmods' => $self->{attrs}->{ramfs_firmmods} || '',
+ 'preboot_id' => $self->{'preboot-id'} || '',
+ 'boot_uri' => $self->{'boot-uri'} || '',
+ };
+ my $content = "# attributes set by slxconfig-demuxer:\n";
+ foreach my $attr (keys %$initramfsAttrs) {
+ $content .= qq[$attr="$initramfsAttrs->{$attr}"\n];
+ }
+ $self->addCMD( {
+ file => "$self->{'build-path'}/etc/initramfs-setup",
+ content => $content
+ } );
+
+ return;
+}
+
+sub _copyUclibcRootfs
+{
+ my $self = shift;
+
+ my $uclibcRootfs = "$openslxConfig{'base-path'}/share/uclib-rootfs";
+
+ my @excludes = qw(
+ );
+
+ # exclude strace unless this system is in debug mode
+ if (!$self->{'debug-level'}) {
+ push @excludes, 'strace';
+ }
+
+ my $exclOpts = join ' ', map { "--exclude $_" } @excludes;
+
+ $self->addCMD("rsync $exclOpts -rlpt $uclibcRootfs/ $self->{'build-path'}");
+
+ return 1;
+}
+
+sub _copyPrebootSpecificFiles
+{
+ my $self = shift;
+
+ # write secondary rootfs-layer (including init) on top of base layer
+ my $prebootRootfs
+ = "$openslxConfig{'base-path'}/share/boot-env/preboot/uclib-rootfs";
+ $self->addCMD("rsync -rlpt $prebootRootfs/ $self->{'build-path'}");
+
+ return 1;
+}
+
+1;
diff --git a/src/boot-env/OpenSLX/MakeInitRamFS/Engine/SlxBoot.pm b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/SlxBoot.pm
new file mode 100644
index 00000000..1334c444
--- /dev/null
+++ b/src/boot-env/OpenSLX/MakeInitRamFS/Engine/SlxBoot.pm
@@ -0,0 +1,264 @@
+# Copyright (c) 2006-2008 - OpenSLX GmbH
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# MakeInitialRamFS::Engine::SlxBoot.pm
+# - provides driver engine for MakeInitialRamFS API, implementing the
+# standard slx boot behaviour (i.e. booting a system remotely).
+# -----------------------------------------------------------------------------
+package OpenSLX::MakeInitRamFS::Engine::SlxBoot;
+
+use strict;
+use warnings;
+
+use base qw(OpenSLX::MakeInitRamFS::Engine::Base);
+
+use File::Find;
+
+use OpenSLX::Basics;
+use OpenSLX::Utils;
+
+################################################################################
+### implementation methods
+################################################################################
+sub _collectCMDs
+{
+ my $self = shift;
+
+ $self->{CMDs} = [];
+
+ $self->_setupBuildPath();
+
+ $self->_addRequiredFSMods();
+
+ $self->_writeInitramfsSetup();
+ $self->_writeSlxSystemConf();
+
+ $self->_copyUclibcRootfs();
+ $self->_copyHwinfo();
+ $self->_copyDistroSpecificFiles();
+ $self->_copyInitramfsFiles();
+
+ $self->_copyPreAndPostinitFiles();
+
+ $self->_calloutToPlugins();
+
+ $self->{distro}->applyChanges($self);
+
+ $self->_copyKernelModules();
+
+ $self->_createInitRamFS();
+
+ return;
+}
+
+sub _setupBuildPath
+{
+ my $self = shift;
+
+ my $buildPath = "$openslxConfig{'temp-path'}/slx-initramfs";
+ $self->addCMD("rm -rf $buildPath");
+
+ my @stdFolders = qw(
+ bin
+ dev
+ etc
+ etc/init-hooks
+ lib
+ mnt
+ proc
+ root
+ sbin
+ sys
+ tmp
+ usr/share
+ var/lib
+ var/lib/nfs/state
+ var/run
+ );
+ $self->addCMD(
+ 'mkdir -p ' . join(' ', map { "$buildPath/$_"; } @stdFolders)
+ );
+
+ $self->{'build-path'} = $buildPath;
+
+ return;
+}
+
+sub _copyDistroSpecificFiles
+{
+ my $self = shift;
+
+ my $distroSpecsPath = "$openslxConfig{'base-path'}/share/distro-specs";
+
+ my $distroName = $self->{'distro-name'};
+ my $distroVer = $self->{'distro-ver'};
+
+ # concatenate default- and distro-specific functions into one file
+ my $functions = slurpFile("$distroSpecsPath/$distroName/functions-default");
+ $functions .= "\n";
+ $functions .= slurpFile(
+ "$distroSpecsPath/$distroName/functions-$distroVer",
+ { failIfMissing => 0 }
+ );
+ $self->addCMD( {
+ file => "$self->{'build-path'}/etc/distro-functions",
+ content => $functions,
+ } );
+
+ return 1;
+}
+
+sub _copyUclibcRootfs
+{
+ my $self = shift;
+
+ my $uclibcRootfs = "$openslxConfig{'base-path'}/share/uclib-rootfs";
+
+ my @excludes = qw(
+ dialog
+ kexec
+ libcurses.so*
+ libncurses.so*
+ mconf
+ );
+
+ # exclude strace unless this system is in debug mode
+ if (!$self->{'debug-level'}) {
+ push @excludes, 'strace';
+ }
+
+ my $exclOpts = join ' ', map { "--exclude $_" } @excludes;
+
+ $self->addCMD("rsync $exclOpts -rlpt $uclibcRootfs/ $self->{'build-path'}");
+
+ return 1;
+}
+
+sub _copyHwinfo
+{
+ my $self = shift;
+
+ my $baseDir = "$openslxConfig{'base-path'}/share/ramfstools/hwinfo";
+
+ my $version = $self->{distro}->determineMatchingHwinfoVersion(
+ $self->{'distro-ver'}
+ );
+
+ # copy db modifications
+ $self->addCMD("tar xfz $baseDir/db/hwinfo.db.tgz -C $self->{'build-path'}/");
+
+ $self->addCMD("cp $baseDir/bin/hwinfo-$version $self->{'build-path'}/usr/bin/hwinfo");
+ my $libHD = "libhd.so.$version";
+ $self->addCMD("cp $baseDir/lib/$libHD $self->{'build-path'}/usr/lib");
+ my $libName = $libHD;
+ while($libName =~ s{\.\d+$}{}g) {
+ $self->addCMD("ln -sf $libHD $self->{'build-path'}/usr/lib/$libName");
+ }
+
+ return 1;
+}
+
+sub _copyInitramfsFiles
+{
+ my $self = shift;
+
+ my $initramfsPath = "$openslxConfig{'base-path'}/share/initramfs";
+
+ find(
+ {
+ wanted => sub {
+ my $len = length($initramfsPath);
+ my $file = $File::Find::name;
+ my $relName = length($file) > $len ? substr($file, $len+1) : '';
+ if (-d) {
+ $self->addCMD("mkdir -p $self->{'build-path'}/$relName");
+ } elsif (-l $file) {
+ my $target = readlink $file;
+ $self->addCMD(
+ "ln -sf $target $self->{'build-path'}/$relName"
+ );
+ } elsif (qx{file $file} =~ m{ELF}) {
+ $self->addCMD(
+ "cp -p $file $self->{'build-path'}/$relName"
+ );
+ } else {
+ my $text = slurpFile($file, { 'io-layer' => 'bytes' } );
+
+ # replace macros
+ # TODO: find out what these mean and maybe find a
+ # different, better solution
+ my %macro = (
+ 'COMDIRINDXS' => '/tmp/scratch /var/lib/nobody',
+ # keep serverip as it is (it is handled by init itself)
+ 'serverip' => '@@@serverip@@@',
+ );
+ $text =~ s{\@\@\@([^\@]+)\@\@\@}{
+ if (!exists $macro{$1}) {
+ warn _tr(
+ 'unknown macro @@@%s@@@ found in %s',
+ $1, $File::Find::name
+ );
+ '';
+ } else {
+ $macro{$1};
+ }
+ }eogms;
+
+ # force shebang with ash (deprecated with new busybox)
+ #$text =~ s{\A#!\s*/bin/.+?$}{#!/bin/ash}ms;
+
+ $self->addCMD( {
+ file => "$self->{'build-path'}/$relName",
+ content => $text,
+ mode => (-x $file ? 0755 : undef),
+ } );
+ }
+ },
+ no_chdir => 1,
+ },
+ $initramfsPath
+ );
+
+ return;
+}
+
+sub _copyPreAndPostinitFiles
+{
+ my $self = shift;
+
+ foreach my $cfg (
+ 'default/initramfs/preinit.local',
+ "$self->{'system-name'}/initramfs/preinit.local",
+ 'default/initramfs/postinit.local',
+ "$self->{'system-name'}/initramfs/postinit.local"
+ ) {
+ my $cfgPath = "$openslxConfig{'private-path'}/config/$cfg";
+ next if !-f $cfgPath;
+ $self->addCMD("cp -p $cfgPath $self->{'build-path'}/bin/");
+ }
+ return;
+}
+
+sub _addRequiredFSMods
+{
+ my $self = shift;
+
+ my $osExportEngine = instantiateClass("OpenSLX::OSExport::Engine");
+ $osExportEngine->initializeFromExisting($self->{'export-name'});
+ my $fsMods = $self->{attrs}->{ramfs_fsmods} || '';
+ foreach my $fsMod ($osExportEngine->requiredFSMods()) {
+ $fsMods .= " $fsMod" if $fsMods !~ m{$fsMod};
+ }
+ $self->{attrs}->{ramfs_fsmods} = $fsMods;
+
+ return;
+}
+
+1;