# COPYRIGHT_NOTICE_START
# Licensed Materials - Property of IBM
# "Restricted Materials of IBM" -- 5746-SM2
# (C) Copyright IBM Corp. 2007, 2008 All Rights Reserved.
# US Government Users Restricted Rights - Use, duplication or disclosure
# restricted by GSA ADP Schedule Contract with IBM Corp.
# COPYRIGHT_NOTICE_END

package Maiken::RO::RHEL;
use base 'Maiken::RO';

=head1 NAME

  Maiken::RO::RHEL - IBM PowerVM Lx86 installation for Red Hat EL

=cut

use strict;
use warnings;

sub RH_REG_FILE           { 'redhat-activation-detail'                   }
sub RH_REGISTER_EMAIL     { 'pave@redhat.com'                  }
sub INIT_D                { '/etc/rc.d/init.d' }
sub DEFAULT_SELINUX_TRANS { 'n' }

sub initialize {
  my ($self) = @_;
  $self->SUPER::initialize;
}

sub CONFIG_DEFAULTS {
  my $defaults = $_[0]->SUPER::CONFIG_DEFAULTS;
  push @$defaults, {
    key => 'selinux_trans_enabled',
    var => 'ENABLE_SELINUX_TRANSITIONS',
    default => 'DEFAULT_SELINUX_TRANS',
    askif => sub { 0 },
  };
  return $defaults;
}


=item B<get_distro_registration_info_interactively>

Called exclusively by get_registration_info_interactively.
Sends an email to RedHat

=cut

sub get_distro_registration_info_interactively {
  my ($self) = @_;
  my @qs =
    (
     [rh_company_name => "Please enter the name of your company:",
     '.+', 'A company name must be provided.', 'ibm_company_name'],
     [rh_registrant_name => "Please enter your name:",
      '.+', 'You must provide your name.', 'ibm_registrant_name'],
     [rh_email_address => "Please enter your email address:",
      $self->EMAIL_REGEXP, 'The email address is compulsory and must have an @ and a valid domain.',
      'ibm_email_address'],
     [rhn_login => "Please enter your RHN login (optional):",
      '([^+%"<^>|\\$()]+)?',
     'RHN login cannot contain any of the following: +%\"<^>|\\$()'],
     [rh_account_number => "Please enter your Red Hat account number (optional):",
      '(\d{6})?', 'Account numbers must contain exactly 6 digits.'],
    );

  my $initial_text = qq{
The Linux/x86 binaries and libraries in the x86 World can be kept up to date
using the Red Hat Network.  To receive this support, you must upgrade your
current Red Hat subscription to support both Linux/x86 and Linux/POWER.
This upgrade is at no additional charge.

To upgrade the subscription on this system, you need to provide some
information that will be emailed to Red Hat Inc.  Once this has been sent,
you will receive an acknowledgement email from Red Hat within approximately
the next 24 hours (1 business day).  You will then receive another email 
confirming that the subscription has been upgraded within approximately 48 
hours (2 business days). 

};

  return $self->register_interactively
    (
     email                       => $self->RH_REGISTER_EMAIL,
     organisation                => 'Red Hat Inc.',
     record_file                 => "$self->{config}{config_dir}/".
                                      $self->RH_REG_FILE,
     subject_line_method         => 'rh_subject_line',
     email_body_method           => 'rh_registration_text',
     questions                   => \@qs,
     initial_text_for_first_time => $initial_text,
     compulsory                  => 0,
    );
}

=item B<rh_registration_text>

Returns a string containing the contents of the registration
email to be sent to RH.

=cut

sub rh_registration_text {
  my ($self) = @_;
  my $c = $self->{config};
  my $text = qq{
Date:         $c->{registration_date}

Company:      $c->{rh_company_name}
RHN Login:    $c->{rhn_login}
Account No:   $c->{rh_account_number}

Name:         $c->{rh_registrant_name}
Email:        $c->{rh_email_address}
};
  return $text;
}

=item B<finalize_sw_installation>

As the superclass but run clean_rc_dirs at the beginning.

=cut

sub finalize_sw_installation {
  my ($self) = @_;
  # Let's clear rcX.d
  $self->clean_rc_dirs;
  $self->SUPER::finalize_sw_installation;
}

=item B<clean_rc_dirs>

Cleans the rcX.d dirs

=cut

sub clean_rc_dirs {
  my ($self) = @_;
  # It is probably safer to disable all services using
  # chkconfig and then - to get rid of the reboot, halt and single
  # scripts - unlink *
  my $command = "/sbin/chkconfig";
  # what services do we have?
  my @service_list = split /\n/,$self->run_translated($command, '--list');
  if( $self->{exit} == 0 ) {
    foreach my $line (@service_list) {
      # Ignore blank/whitespace lines
      next if $line =~ /^\s*$/;
      # The only way we can match the "xinetd services installed" is
      # to say it is the line with /xinetd/ but not /5:/. This is
      # because xinetd is the only reliable word that is not localized
      # into the user's language.
      next if $line =~ /xinetd/ and $line !~ /5:/;
      $line =~ /\s*(.*?)\s+.*/;
      my $service_name = $1;
      $service_name =~ s/://g;
      my $msg = $self->run_translated($command, $service_name, 'off');
      if( $self->{exit} != 0 ) {
	$self->log("WARNING: [_1]'s startup state could not be set.", $service_name);
      }
    }
    # now, unlink * to delete the scripts that chkconfig
    # did not delete (halt, reboot, etc)
    my $scripts_dir = "$self->{config}{sw_root_path}/etc/rc.d";
    for my $i (0..6) {
      my @dir_list = glob("\Q$scripts_dir/rc$i.d\E/*");
      foreach my $file (@dir_list) {
        # rc.local is kept
        unless( $file =~ /S99local$/ ) {
          unlink $file;
        }
      }
    }
    $self->enable_services;
  } else {
    $self->log("WARNING: The list of services could not be retrieved.");
  }
}

=item B<setup_sw>

As the superclass but also copy the /etc/sysconfig/network file into the x86 World at the end,
and restore the file contexts of files in /etc and /var.

=cut

sub setup_sw {
  my ($self) = @_;
  $self->SUPER::setup_sw;

  # Copy the native /etc/sysconfig/network file into the x86 World.
  my $network_file = "/etc/sysconfig/network";

  if (-f $network_file) {
    File::Copy::copy($network_file, "$self->{config}{sw_root_path}/$network_file")
     or $self->log("Warning - failed to create [_1]", $network_file);
  }

  # Some files aren't owned by rpms. Restore the contents of a few specific things as well.
  # This is done here so that it also restores files the installer has created; eg /var/log/wtmp.
  $self->log_only_to_file($self->run_translated('/sbin/restorecon', '-vR', '/etc', '/var', '2>&1'));
}

=item B<rh_subject_line>

Returns a string containing the subject line for the 
redhat registration email to be sent to RH.

=cut

sub rh_subject_line {
  my ($self) = @_;

  return 'Red Hat Subscription Upgrade for PowerVM Lx86';
}


=item B<check_login_defs>

See superclass. The RPM is shadow-utils.

=cut

sub check_login_defs {
  my $self = shift;
  my $rpm = shift;
  if (defined $rpm && ($rpm =~ /shadow-utils/)) {
    $self->modify_login_defs;
  }
}


=item B<configure_sw_post_base_rpms>

Restores the selinux file contexts for all rpms installed up to this point.

=cut

sub configure_sw_post_base_rpms {
  my $self = shift;
  $self->log_only_to_file($self->run_translated('/bin/bash', '-c', '/bin/rpm -qla | /sbin/restorecon -v -f -', '2>&1'));

  # See also setup_sw, which makes a further call to restorecon.
}

=item B<do_registration_noninteractively>

As in the parent class but also does the RedHat Network registration
if do_redhat_registration is passed as a true parameter.

=cut

sub do_registration_noninteractively {
  my ($self, %opts) = @_;
  $self->SUPER::do_registration_noninteractively(%opts);

  if ($opts{do_redhat_registration}) {
    $self->register_noninteractively
      (
       email                       => $self->RH_REGISTER_EMAIL,
       organisation                => 'Red Hat Inc.',
       record_file                 => "$self->{config}{config_dir}/".
                                        $self->RH_REG_FILE,
       subject_line_method         => 'rh_subject_line',
       email_body_method           => 'rh_registration_text',
       force                       => $opts{force},
      );
  }
}

=item B<bind_qt_and_sw>

Call the superclass version, and also warn about selinux if it isn't enabled yet.

=cut

sub bind_qt_and_sw {
  use utf8; # make sure the string literal is in utf8 - not strictly
            # necessary here but you never know, eh?

  my ($self) = @_;
  $self->SUPER::bind_qt_and_sw or return 0;

  # If ENABLE_SELINUX_TRANSITIONS isn't set to y in the config, warn the user that they 
  # will have to manually enable it if they want selinux functionality.
  if (lc($self->{config}{selinux_trans_enabled}) ne "y") {
    $self->log("Note: SELinux is not enabled by default for PowerVM Lx86 after installation.\nIf SELinux is enabled on your Power system, you can enable SELinux for x86\napplications by enabling the SELinux configuration switches in the PowerVM Lx86\nconfiguration file.  Please see the Administration Guide for details.");
  }

  # Add a file context for the subject world, wherever it happened to be installed.
  # Also add a context for anything inside the subject world, so that target
  # relabels don't mess with the subject world.
  # We add a couple of lines to lx86.fc and (for rhel4) to each of the 
  # file_contexts files.
  my $selinuxPath = $self->{config}{qt_root_path};
  my $swroot = $self->{config}{sw_root_path};
  my $lx86fcFile = "$selinuxPath/selinux/lx86.fc";
  my $rootLine;
  my $worldLine = "$swroot/.*        <<none>>\n";
  my @files;
  push @files,$lx86fcFile;

  if ($self->{distribution} =~ /RHEL5/) {
    $rootLine  = "$swroot        -d system_u:object_r:root_t:s0\n";
  }
  elsif ($self->{distribution} =~ /RHEL4/) {
    $rootLine  = "$swroot        -d system_u:object_r:root_t\n";
    
    foreach my $file (<$selinuxPath/selinux/rhel4*/file_contexts>) {
      push @files,$file;
    }
  }
  else {
    # Unsupported future OS?  We shouldn't get here.
    $self->croak("Unexpected OS ([_1]) found in bind_qt_and_sw\n", $self->{distribution});
  }

  foreach my $file (@files) {
    $self->write_file($file, "$rootLine$worldLine\n", undef, (mode => '>>', warnOnly => 1));
  }

  # On RHEl5, also rebuild lx86.pp with the new file contexts
  if ($self->{distribution} =~ /RHEL5/) {
    my $semoduleOutput = $self->run_command("/usr/bin/semodule_package", "-f", $lx86fcFile, "-o", "$selinuxPath/selinux/lx86.pp", "-m", "$selinuxPath/selinux/lx86.mod");
    $self->log_only_to_file($semoduleOutput);
  }

  return 1;
}


=item B<check_selinux_is_disabled>

Return 1 if selinux is disabled; otherwise log an error and return 0.

=cut

sub check_selinux_is_disabled {
  my ($self) = @_;
  
  # Don't let them install if ENABLE_SELINUX_TRANSITIONS is set to y.
  # Installs won't work with selinux transitions on.
  if ($self->{config}{install_sw} and (lc($self->{config}{selinux_trans_enabled}) eq "y")) {
    $self->log;
    $self->log("Installation of an x86 World requires that SELinux be disabled for PowerVM Lx86.\nPlease set ENABLE_SELINUX_TRANSITIONS=n in the PowerVM Lx86 config file and try\nagain.");
    return 0;
  }
  
  return 1;
}
  
=item B<sanity_install_config>

Call the superclass version, and additionally check that SE Linux isn't set in the config.

=cut

sub sanity_install_config {
  my ($self, $modifiers) = @_;

  $self->SUPER::sanity_install_config($modifiers) or return 0;
  $self->check_selinux_is_disabled or return 0;
  
  return 1;
}


=item B<get_subject_world_config_interactively>

Call the superclass version, and additionally check that SE Linux isn't set in the config.

=cut

sub get_subject_world_config_interactively {
  my ($self) = @_;
  
  $self->check_selinux_is_disabled or return 0;
  $self->SUPER::get_subject_world_config_interactively or return 0;
  
  return 1;
}

1;
