#!/usr/bin/perl -w
#  update-rcconf-guide
#                   Copyright (c) 2004-2009 kamop@debian.org
#

=head1 NAME

update-rcconf-guide - Create default guide file for rcconf

=head1 SYNOPSIS

B<update-rcconf-guide>

=head1 DESCRIPTION

B<Update-rcconf-guide> creates the default guide file which B<rcconf> uses.

B<Update-rcconf-guide> searches the package names corresponding to each
service file in /etc/init.d directory from dpkg info 
files(/var/lib/dpkg/info/*.list) and get the description of these packages
using apt-cache. B<Update-rcconf-guide> uses Short-Description in priority
to the description if service files has Short-Description field.
B<Update-rcconf-guide> writes those results to /var/lib/rcconf/guide.default
file.

You can write your own guide in user guide file(/var/lib/rcconf/guide) by hand.
B<Rcconf> refers Guides in /var/lib/rcconf/guide before those in
/var/lib/rcconf/guide.default.

If you install some packages after executed B<update-rcconf-guide>, 
you need to re-create this file using B<update-rcconf-guide> so as to refresh
guide.default that includes new guides for installed new services.

Notice: B<update-rcconf-guide> was not executed when you installed B<rcconf>
        package.

=head1 FILE

=over 8

=item /var/lib/rcconf/guide.default

Guide File update-rcconf-guide generates.

=item /var/lib/rcconf/guide

Guide File user(Administrator) can define.

=back

=head1 SEE ALSO

rcconf(8)

=head1 AUTHOR

Atsushi KAMOSHIDA <kamop@debian.org>

=cut

use strict;
use FileHandle;
use DirHandle;

my @unselects = ("\^\\\.\$", "\^\\\.\\\.\$", "\^rc\$", "\^rcS\$", "\^README\$",
                  "\^skeleton\$", ".*\\\.dpkg-dist\$", ".*\\\.dpkg-old\$",
                  ".*\\\.dpkg-bak\$", ".*\\\.sh\$");

my $APTCACHE_BIN = "/usr/bin/apt-cache";
my $GREP_BIN = "/bin/grep";

my $RCCONF_DIR = "/var/lib/rcconf";
my $GUIDE_FILE = $RCCONF_DIR."/guide.default";
my $INITD_DIR = "/etc/init.d";

if ( ! -d $RCCONF_DIR ) {
  die "Can't file rcconf dir($RCCONF_DIR).\n";
}

print "Reading $INITD_DIR and getting package description ...\n";

my $initd_files_array = &read_initd_dir($INITD_DIR);

my $filepath_hash = &create_dpkg_installed_filepath("/var/lib/dpkg/info");

print "Writing package default guide to $GUIDE_FILE ...\n";

my $fh = FileHandle->new(">".$GUIDE_FILE);
if ( ! defined($fh) ) {
  die "Can't open file: $GUIDE_FILE .\n";
}

my $path;
my $description_header;
foreach my $initd_file ( @{$initd_files_array} ) {
#  print $initd_file."\n";
  next if ( &check_unselect($initd_file, \@unselects) == 1 );
#  print $initd_file."\n";
  $path = $INITD_DIR."/".$initd_file;
  next if ( ! exists($filepath_hash->{$path}) );
  $description_header = &get_description_header($filepath_hash->{$path}, $path);
  if ( $description_header ne "" ) {
    print $fh $initd_file." ".$description_header."\n";
  }
}

undef $fh;

print "Done.\n";

exit;

#######################################################################
## MODULE: get_description_header
## DESC: 
## IN:
## OUT: 
## OP:
## STATUS:
## END:
sub get_description_header {
  my ($package, $path) = @_;
##
  if ( $package eq "" ) {
    die "arg(package) is null.\n";
  }

  ## First, try to get Short-Description
  my $line = `$GREP_BIN '^\# Short-Description:' $path`;
  if ( $line ne "" ) {
    $line =~ /^\# Short-Description:\s*(.*)/;
    return $1;
  }

  if ( $package eq "tinyproxy" ) {
    printf "%s %s %s\n", $package, $path, $line;
    exit 1;
  }

  $line = `$APTCACHE_BIN show $package | $GREP_BIN '^Description:'`;
  $line =~ /^Description:\s*(.*)/;

  return $1;
} ## get_description_header

#######################################################################
## MODULE: check_unselect
## DESC: Check if 'file' exists in unselects array.
## IN:
## OUT:  results 0 := file is not in the array.
##               1 := file exists in the array.
## OP:
## STATUS:
## END:
sub check_unselect{
  my ($file, $unselects) = @_;
##
  return 1 if ( ! -x $INITD_DIR . "/" . $file );

  my $unselect;
  foreach $unselect ( @{$unselects} ) {
    return 1 if ( $file =~ /$unselect/ );
  }
  return 0;
} ## check_unselect


#######################################################################
## MODULE: read_initd_dir
## DESC: Collect files in init.d/ directory.
## IN:
## OUT:
## OP:
## STATUS:
## END:
sub read_initd_dir{
  my ($initd_dir) = @_;
##
  if ( ( $initd_dir eq "" ) || ( ! -d $initd_dir ) ) {
    die "No such directory: $initd_dir .\n";
  }

  my $dh = DirHandle->new($initd_dir);
  if ( ! defined($dh) ) {
    die "No such directory: $initd_dir .\n";
  }

  my $file;
  my @dirs = ();
  while ( defined($file = $dh->read()) ) {
    push(@dirs, $file);
  }

  undef $dh;

  return(\@dirs);
} ## read_initd_dir

#######################################################################
## MODULE: read_initd_dir
## DESC: Collect files in inet.d/ directory.
## IN:
## OUT:
## OP:
## STATUS:
## END:
sub create_dpkg_installed_filepath {
  my ($info_dir) = @_;
##
  if ( ( $info_dir eq "" ) || ( ! -d $info_dir ) ) {
    die "No such directory: $info_dir .\n";
  }

  my $dh = DirHandle->new($info_dir);
  if ( ! defined($dh) ) {
    die "Can't open directory: $info_dir .\n";
  }

  my $file;
  my $package;
  my %filepath_hash = ();
  while ( defined($file = $dh->read()) ) {
    if ( $file =~ /(.*)\.list$/ ) {
      $package = $1;
#      print "$package $file\n";
      &insert_filepath($info_dir."/".$file, \%filepath_hash, $package);
    }
  }
  undef $dh;

  return(\%filepath_hash);
} ## create_dpkg_installed_filepath

#######################################################################
## MODULE: insert_filepath
## DESC: 
## IN:
## OUT:
## OP:
## STATUS:
## END:
sub insert_filepath {
  my ($info_filelist_file, $filepath_hash, $package) = @_;
##
  if ( ( $info_filelist_file eq "" ) || ( ! -f $info_filelist_file ) ) {
    die "No such directory: $info_filelist_file.\n";
  }
  if ( ref($filepath_hash) ne "HASH" ) {
    die "arg(filepath_hash) isn't HASH ref.\n";
  }
  if ( $package eq "" ) {
    die "arg(package) is null.\n";
  }

  my $fh = FileHandle->new($info_filelist_file);
  if ( ! defined($fh) ) {
    die "Can't open $info_filelist_file.\n";
  }

  my $line;
  while ( $line = <$fh> ) {
    ## If we check $line whether file or not, go very slowly.
    chomp($line);
    $filepath_hash->{$line} = $package;
  }

  undef $fh;
} ## insert_filepath
