#!/usr/bin/perl
# Merge in a new SELinux policy.
# Written by Russell Coker (This file needs a copyright statement!)
# Modifications to support new debconf by Colin Walters <walters@debian.org>
use strict;

my $method = $ARGV[0];
#$method || die "Usage: policy-update METHOD";

exit 0 if ($method eq "Don't Touch");

chdir("/usr/share/selinux/policy");
my %newfiles = readfile("newfiles");
my %delfiles = readfile("delfiles");
my %ignorediff = readfile("ignorediff");
chdir("default") or die "Can't access directory default";
my %default = findit();
chdir("../current") or die "Can't access directory current";
my %current = findit();
chdir("..") or die "Can't change directory";

my $file;
# sort out saved list of new files
foreach $file (keys %newfiles)
{
# if file doesn't exist or if it's in the default dir then it's not a new file
  if($current{$file} != 1 or $default{$file} == 1)
  {
    $newfiles{$file} = 0;
  }
  else
  {
# if file exists and it's not in the default dir then it's a new file and
# remove it from the current file list
    $current{$file} = 0;
  }
}

# sort out saved list of deleted files
foreach $file (keys %delfiles)
{
# if default directory doesn't have the file or if the file exists then it's
# not a deleted file
  if($default{$file} != 1 or $current{$file} == 1)
  {
    $delfiles{$file} = 0;
  }
  else
  {
# if default directory has the file and it doesn't exist then it's a deleted
# file and remove it from the default list
    $default{$file} = 0;
  }
}

# check for new files
foreach $file (keys %default)
{
  if( ($default{$file} == 1) and ($current{$file} != 1) )
  {
    my $in;
    LOOP: while(1)
    {
      print("New file: $file, Copy/Display/Ignore [c/d/I]? \n");
      $in = lc(substr(<STDIN>, 0, 1));
      SWITCH: {
        if($in =~ /c/ ) { `cp default/$file current/$file`; last LOOP; }
        if($in =~ /d/) { system("less default/$file"); last SWITCH; }
        $delfiles{$file} = 1;
        $default{$file} = 0;
        last LOOP;
      }
    }
  }
}
open(OUT, ">delfiles") or die "Can't write to list of deleted files.";
foreach $file (keys %delfiles)
{
  if($delfiles{$file} == 1)
  {
    printf(OUT "%s\n", $file) or die "Can't write to file";
  }
}
close(OUT);

# check for deleted files
foreach $file (keys %current)
{
  if( ($current{$file} == 1) and ($default{$file} != 1) )
  {
    my $in;
    LOOP: while(1)
    {
      print("Upstream deletion or custom file: $file, Delete/Ignore [d/I]? \n");
      $in = lc(substr(<STDIN>, 0, 1));
      SWITCH: {
        if($in =~ /d/) { system("rm current/$file"); last LOOP; }
        $newfiles{$file} = 1;
        $current{$file} = 0;
        last LOOP;
      }
    }
  }
}
open(OUT, ">newfiles") or die "Can't write to list of new files.";
foreach $file (keys %newfiles)
{
  if($newfiles{$file} == 1)
  {
    printf(OUT "%s\n", $file) or die "Can't write to file";
  }
}
close(OUT);

foreach $file (keys %default)
{
  my $rc = 0;
  if($default{$file} == 1 and $ignorediff{$file} != 1)
  {
    $rc = system("cmp default/$file current/$file > /dev/null");
  }
  if($rc != 0)
  {
    my $in;
    LOOP: while(1)
    {
      print("File \"$file\" changed.\nCopy/Ignore/Always ignore/view Diff [c/I/a/d]? \n");
      $in = lc(substr(<STDIN>, 0, 1));
      SWITCH: {
        if($in =~ /c/ ) { `cp default/$file current/$file`; last LOOP; }
        if($in =~ /d/) { system("diff -u current/$file default/$file | less"); last SWITCH; }
        if($in =~ /a/) { $ignorediff{$file} = 1; last LOOP; }
        last LOOP;
      }
    }
  }
}

open(OUT, ">ignorediff") or die "Can't write to list of ignore diff files.";
foreach $file (keys %ignorediff)
{
  if($ignorediff{$file} == 1)
  {
    printf(OUT "%s\n", $file) or die "Can't write to file";
  }
}
close(OUT);



sub findit
{
  open(INPUT, "find . -type f 2> /dev/null |") or die "Can't find.";
  my %files = ();
  while(<INPUT>)
  {
    chomp;
    $_ =~ s/^..//;
    if(not $_ =~ /^tmp/ and not $_ =~ /^policy/ and not $_ =~ /^.$/
      and not $_ =~ /file_contexts\/file_contexts/)
    {
      $files{$_} = 1;
    }
  }
  close(INPUT);
  return %files;
}

sub readfile
{
  open(INPUT, "<" . $_[0]) or return ();
  my %files = ();

  while(<INPUT>)
  {
    chomp;
    $files{$_} = 1;
  }
  close(INPUT);
  return %files;
}
