#!/usr/bin/perl -w

#    make_debian Copyright (C) 2001 from gBootRoot
#    Lead Developer and Project Coordinator
#    Jonathan Rosenbaum <freesource@users.sourceforge.net>
#
#    http://gbootroot.sourceforge.net

#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.

#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.

#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


# You will need to get dswim at http://www.sourceforge.net/projects/avd
my $home = "$ENV{HOME}/.gbootroot";
my $home_yard = "$home/yard";
my $template_dir = "$home_yard/templates/";
my $home_yard_replacements = "$home_yard/Replacements";
my $nodename = `uname -n`; chomp $nodename;
my $debian_yard = "Debian-$nodename.yard";
my $status = "/var/lib/dpkg/status";
my $info = "/var/lib/dpkg/info";
my (%alternatives, @alternatives); # for checking for alternatives
my %inetd; # checks for inetd binaries.

# You need file-rc, and you may add other extra stuff (@extra_packages).  
# These packages were chosen for woody, so you may need something different.  
# If you add stuff, check for dependencies, empty directories and special 
# configuration files created by the package scripts.
#
# You may have to edit the text below STUFF, i.e. the template.
#
# Dswim provides excellent information for this task.  swim -qT packagename(s)
# & swim -ql --df packagename(s) & swim -qc packagename(s) (not all conf files 
# can  be found this way .. read above) so you will want to use 
# swim -q --scripts packagename(s) or 
# swim -q --preinst --postinst packagenames(s).

# EDIT HERE
my @extra_packages = qw(file-rc dswim apt apt-utils debconf nvi sysklogd
klogd netbase tcpd net-tools portmap netkit-ping netkit-inetd ifupdown less 
perl perl-modules libwrap0 ipchains whiptail libnewt0 libpopt0 debconf-utils
libterm-readline-gnu-perl);
# NEXT EDIT TEMPLATE 

#################################################################
#################################################################
#           
#     EDIT
#    TEMPLATE
#     BELOW 
#  
# Edit below $stuff = << "STUFF" to make changes to the template. 
sub stuff {

my $stuff = << "STUFF";
$Id
# Generated by make_debian.

# This template creates a complete Debian system which is more streamlined 
# than the base.tgz used for normal installations.  Once everything is made, 
# you can use user-mode-linux and apt to tweak the system. 
# Make-debian generates all the information you need.  You will need dswim and 
# file-rc installed, and you will have to be running a Debian system to make 
# this template.  Make_debian ditches info, man, and doc files by default
# and timezone info not found on the host system, but gives you the choice
# to decide otherwise.  

# Characteristics:  user: root passwd: root 
#                   user: user passwd: user
#                   Uses devfs.
    
# IMPORTANT NOTE:  Things slow down noticeably when the buffer gets too big in
# the verbosity box so consider closing it with the slider for faster 
# generation.  There are several ways to accomplish this:  
# Choose Edit->Stages->"user defined" and go one stage at a time, closing 
# the verbosity box with the slider bar between each stage, and then 
# reopen the verbosity box.  If the stage is particularly long, you 
# can toggle the slider bar to close the verbosity box and reopen it
# again clearing the buffer in the process.  You may choose a lower 
# verbosity level, or you may keep the verbosity box off altogether and
# look at /tmp/gbootroot_tmp'time-date'/verbose or 
# /tmp/gboot_non_root_`id -u`/verbose (normal user).

# Todays Quote: Creating a root filesystem is all about stuff.

# The STUFF NEEDED in order for init to work.
/etc/runlevel.conf <=  Replacements/etc/runlevel.conf # made by make_debian
/etc/init.d/rc
/etc/init.d/rcS
/etc/inittab <= Replacements/etc/inittab.debian # specific to devfs
/etc/default/rcS

# Stuff needed to return init to its state prior to installing file-rc.
/etc/init.d/rc.links
/etc/init.d/rcS.links 
/usr/sbin/update-rc.d.links

# Login stuff 
/etc/securetty <= Replacements/etc/securetty.debian # devfs needs this
/root/.bashrc <= Replacements/root/.bashrc.debian
/root/.profile <= Replacements/root/.profile.debian
/home/user/.bashrc <= Replacements/home/user/.bashrc.debian
/home/user/.bash_profile <= Replacements/home/user/.bash_profile.debian
/home/user/README <= Replacements/home/user/README # permissions issue
/etc/hostname <= Replacements/etc/hostname
/etc/motd <= Replacements/etc/motd

# Important stuff  .. you will need to edit the login files if you add packages
# which require other users/groups.  The default fstab mounts /dev/ubd/0.
#/etc/fstab <=  Replacements/etc/fstab.new # Made from Yard Box menu
/etc/fstab <=  Replacements/etc/fstab.debian # devfs specific
/etc/passwd <= Replacements/etc/passwd.debian
/etc/passwd- <= Replacements/etc/passwd-debian
/etc/group <= Replacements/etc/group.debian
/etc/group- <= Replacements/etc/group-debian
/etc/shadow <= Replacements/etc/shadow.debian

# The stuff required by dpkg.
/var/lib/dpkg/diversions <= Replacements/var/lib/dpkg/diversions
/var/lib/dpkg/cmethopt
/var/lib/dpkg/lock
/var/lib/dpkg/status <=  Replacements/var/lib/dpkg/status
/var/lib/dpkg/methods/disk
/var/lib/dpkg/methods/floppy
/var/lib/dpkg/methods/mnt
/var/lib/dpkg/info
/var/lib/dpkg/updates
/var/lib/dpkg/alternatives
/var/lib/dpkg/available <= Replacements/var/lib/dpkg/available

# Stuff needed by apt.
/var/cache/apt/archives/lock
/var/cache/apt/archives/partial
/var/lib/apt/lists/lock
/var/lib/apt/lists/partial
/etc/apt/*

# Timezone data from libc6
/usr/share/zoneinfo/localtime

# Debconf stuff
/var/cache/debconf

# Ipchains stuff
/etc/default/ipchains

# Netkit-inetd stuff
/etc/inetd.conf <= Replacements/etc/inetd.conf

# Tcpd stuff
/etc/hosts.allow
/etc/hosts.deny

# Network stuff
#
# You will want to edit the /etc/network/interfaces file.
# Make sure your host system kernel has the proper capabilities compiled
# or the appropriate module, for instance if tap is used you need the 
# ethertap and netlink_dev modules.
#
# And when you start your creation with the uml box you will want to add
# something like this to the options where HWaddr (see ifconfig) belongs
# to your network device:
#
# eth0=ethertap,tap0,HWaddr,192.168.1.5
#
/etc/resolv.conf 
/etc/hosts <= Replacements/etc/hosts
/root/umlnet <= Replacements/root/umlnet # Example network setup script
/etc/networks <= Replacements/etc/networks
/etc/network/if-down.d      # empty
/etc/network/if-post-down.d # ""
/etc/network/if-pre-up.d    # ""
/etc/network/if-up.d        # ""
/etc/network/interfaces <= Replacements/etc/network/interfaces
/etc/network/options
/etc/network/spoof-protect

# Devices - leaving a console (just in case) and MAKEDEV if you
# want to make devices which will only exist until you reboot or halt
# the system.  If you need devices which last from one invocation to
# the next, install devfsd and edit /etc/devfs/devices. 
/dev/MAKEDEV # a link
/dev/console

#  Empty directories with no stuff.
/dev # paranoid check
/mnt        
/proc               
/tmp                
/var/tmp
/var/run
/var/lock
/var/log/news
/var/lib/locate
/var/backups

# Stuff so ldconfig creates all the proper dependencies.
/etc/ld.so.conf <= Replacements/etc/ld.so.conf

#  User-Mode-Linux modules stuff
#
#  These are modules compiled for the uml kernel version
#  included with gbootroot.  Choose 2.2 or 2.4 depending on
#  which kernel series your are using with your live host system.
#  You may either include the modules archive with the root 
#  filesystem as a replacement and "tar xvf", or untar the
#  modules archive from the host system by mounting it 
#  with "mount -t hostfs none -o \ 
#  /usr/lib/bootroot/yard/Replacements/lib/modules /mnt" 
#  and then "tar xvf /mnt/modules-2.4.tar -C /".
#
#  Then "depmod -ae -F /proc/ksyms" from the running uml kernel.
#
#
#/modules-2.2.tar  <=  Replacements/lib/modules/modules-2.2.tar  
#/modules-2.4.tar  <=  Replacements/lib/modules/modules-2.4.tar

## ALL the REQUIRED files generated by make-debian.
## This is stuff from the required packages, so some files may be
## removed, or some files can be replaced with stuff from say .. busybox.
STUFF

return $stuff;
} # end sub stuff
# STOP EDITING
#################################################################
#################################################################


#########################################
## Collect Information from the System ##
#########################################

use strict;
use File::Basename;
my $rm = "\$";
$main::Id = "# \$Id: make_debian,v 1.60 2001/12/13 05:43:27 freesource Exp $rm"; 
my $sbin = grep(/\/usr\/sbin/,$ENV{'PATH'});
if ($sbin == 0) {
    $ENV{'PATH'} = "/usr/sbin:" . $ENV{'PATH'};
}


# Before starting make sure dswim and file-rc are present.
start_up();

print STDERR "Required packages:\n";
system "swim --search \"Priority: required\" --no";
my $swim_packages = "swim -qS|";
my $swim_list = "swim -qSl|"; # Not using --df for empty directories.
$, = " ";
my $extra_files = "swim -ql @extra_packages|"; # Not using --df.
$, = "";

# All the packages
open(SWIM,$swim_packages) or die "Couldn't open swim_packages: $?\n";
my @required_packages = <SWIM>; chomp @required_packages;
close(SWIM);

# All the files
open(SWIM,$swim_list) or die "Couldn't open swim_list: $!\n";
my @required_files = <SWIM>; chomp @required_files;
close(SWIM);

open(SWIM,$extra_files) or die "Couldn't open extra_files: $!\n";
my @extra_files = <SWIM>; chomp @extra_files;
close(SWIM);

push(@required_files,@extra_files);


###################
## Package Check ##
###################
 
# Better tell the user what required and extra packages don't exist.

# It is 100% unlikely that a required package is missing because
# the information is taken directly from the system. But it is fun
# to test for anyways, weirder things have been known to happen.

my @rpc;
$/ = "";
my @required_stuff = `swim -qi @required_packages`;
$/ = "\n";
foreach my $package_info (@required_stuff) {
    $package_info =~ /^package[:]*\s+([-\+\d\w]+)/i;
    my $p = $1;
    $p =~ s/\+/\\+/g if $p !~ /\\+/g;
    if ( grep(/Status: deinstall|Status: purge|package $p is not installed/,
	     $package_info ) == 1 ) {
	$p =~ s/\\//g if $p =~ /\\+/g;
	push( @rpc, $p ); 
    }    
}

if (@rpc) {
    print STDERR "These are the required packages which were specified:\n\n";
    $, = " ";
    print STDERR @required_packages, "\n\n";
    print STDERR "This is what wasn't installed on your system:\n\n";
    print STDERR @rpc , "\n\n";
    $, = "";
}


my @epc;
$/ = "";
my @extra_stuff = `swim -qi @extra_packages`;
$/ = "\n";
foreach my $package_info (@extra_stuff) {
    $package_info =~ /^package[:]*\s+([-\+\d\w]+)/i;
    my $p = $1;
    $p =~ s/\+/\\+/g if $p !~ /\\+/g;
    if ( grep(/Status: deinstall|Status: purge|package $p is not installed/,
	     $package_info ) == 1 ) {
	$p =~ s/\\//g if $p =~ /\\+/g;
	push( @epc, $p ); 
    }    
}

if (@epc) {
    print STDERR "These are the extra packages which were specified:\n\n";
    $, = " ";
    print STDERR @extra_packages, "\n\n";
    print STDERR "This is what wasn't installed on your system:\n\n";
    print STDERR @epc , "\n\n";
    $, = "";
}

push(@required_packages,@extra_packages);


#######################
## Template Creation ##
#######################

# Ask some questions first.
my $doc_reply = "nothing";
print "The default is to remove /usr/share/{doc,man,info}? [yes or no]: ";
while (<STDIN>) {
    $doc_reply = $_;
    last if $doc_reply eq "yes\n";
    last if $doc_reply eq "no\n";
    if ($doc_reply eq "\n") { $doc_reply = "yes\n"; last; }
    if ($doc_reply ne "yes\n" || $doc_reply  ne "no\n") { 
	print "The default is to remove /usr/share/{doc,man,info}? [yes or no]: ";
    }
}

print "\nThe default is to remove everything in /usr/share/zoneinfo\n" .
    "except for your local settings found in /etc/localtime? [yes or no]: ";
my $localtime_reply = "nothing";
while (<STDIN>) {
    $localtime_reply = $_;
    last if $localtime_reply eq "yes\n";
    last if $localtime_reply eq "no\n";
    if ($localtime_reply eq "\n") { $localtime_reply = "yes\n"; last; }
    if ($localtime_reply ne "yes\n" || $localtime_reply  ne "no\n") { 
	print "The default is to remove everything in /usr/share/zoneinfo\n" .
	    "except for your local settings found in /etc/locatime? [yes or no]: ";
    }
}

system "rm -f $template_dir/$debian_yard";
open(DEBIAN,">$template_dir/$debian_yard") 
	or die "Couldn't open $template_dir$debian_yard: $!\n";
open(FILERC,"/etc/runlevel.conf") or die "No runlevel.conf: $!\n";
my @filerc = <FILERC>;
close(FILERC);

print DEBIAN stuff();

my @file_rc;
alternatives();
inetd_in();
foreach (@required_files) {
    if (-e && !-d) {
	if ($doc_reply eq "no\n") {
	    if ($alternatives{$_}) {
		push(@alternatives,$_);
	    }
	    if ($inetd{$_}) {
		$inetd{$_} = 1;
	    }
	    if ($localtime_reply eq "yes\n") {
		    print DEBIAN "$_\n" if ! m,/usr/share/zoneinfo,;
	    }
	    else {
		print DEBIAN "$_\n";
	    }
	}
	else {
	    if (! m,/usr/share/info|/usr/share/man|/usr/share/doc|/usr/X11R6/man,) {
		if ($alternatives{$_}) {
		    push(@alternatives,$_);
		}
		if ($inetd{$_}) {
		    $inetd{$_} = 1;
		}
		if ($localtime_reply eq "yes\n") {
		    print DEBIAN "$_\n" if ! m,/usr/share/zoneinfo,;
		}
		else {
		    print DEBIAN "$_\n";
		}
	    }
	}
	if (m,/etc/init\.d,) {
	    foreach my $filerc (@filerc) {
		     push(@file_rc,$filerc) if $filerc =~ /$_/;		
	    }
	}		   
    }
}
inetd_out();

print DEBIAN "\n# Scripts associated with packages found in info/*\n";
print DEBIAN status_info_divert();

# alternatives
print DEBIAN "\n# Alternative stuff.\n";
foreach (@alternatives) {
    if ($alternatives{$_}) {
	foreach my $alt ( 0 .. $#{ $alternatives{$_} } ) {
	    print DEBIAN "/etc/alternatives/", 
	    $alternatives{$_}[$alt], "\n";
	    print DEBIAN "/var/lib/dpkg/alternatives/", 
	    $alternatives{$_}[$alt], "\n";
	    print DEBIAN dirname($_), "/", 
	    $alternatives{$_}[$alt], "\n";
	}
    }
}

close(DEBIAN);
print  STDERR "All done making your $debian_yard template.\n";

#########################
# END TEMPLATE CREATION #
#########################

# This creates a tweaked runlevel.conf which is easier then trying to figure
# out which symlinks to use in /etc/rc?d.

open(MY_FILERC,">$home_yard_replacements/etc/runlevel.conf") 
    or die "Couldn't open $home_yard_replacements/etc/runlevel.conf: $!\n"; 
my @sortedrc = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ (split(/\s/,$_))[0], $_ ] }
@file_rc;
print MY_FILERC "$main::Id\n";
print MY_FILERC "# GENERATED BY MAKE_DEBIAN\n\n";
print MY_FILERC @sortedrc;
close(MY_FILERC);

# This creates a status file for use by dpkg and swim.
# Although swim could be used to do this, it is more efficient just to
# parse the status file.  But because this is a good exercise for
# using this script to create a status file found from packages on a system 
# which doesn't actually have a status file .. here would be the order 
# needed when using swim to query:
#
# Package, Status, Priority, Section, Installed-Size, Maintainer, Source, 
# Version, Replaces, Provides, Depends, Pre-Depends, Recommends, Suggests,
# Conflicts, Conffiles, Description.
#
# Conffiles would have to be handled both before and after Root Filesystem
# creation so that their md5sums could be accounted for in status.
#
# And this finds all the scripts associated with a package in info/*,
# creates an empty available file, and creates the diversions file.

sub status_info_divert {

$/ = "";
open(STATUS,"$status") or die "Can't find /var/lib/dpkg/status: $!\n";
home_builder("$home_yard_replacements/var/lib/dpkg");
system "touch $home_yard_replacements/var/lib/dpkg/available";
    #or die "Couldn't create Replacements/var/lib/dpkg/available: $!\n";
open(NEW_STATUS,">$home_yard_replacements/var/lib/dpkg/status")
    or die "Couldn't open $home_yard_replacements/var/lib/dpkg/status: $!\n";
while (<STATUS>) { # keep the order
    my $stat = $_;
    my $stat2 = (split(/\n/,$stat))[0]; # might as well
    foreach my $rp (@required_packages) {
	$rp = (split(/_/,$rp))[0];
	# Deal with names with +
	$rp =~ s/\+/\\+/g if $rp !~ /\\+/g;
	if ($stat2 =~ /^Package: $rp$/) {
	    print NEW_STATUS $stat;
	} 
    }
}
close(NEW_STATUS);
close(STATUS);
$/ = "\n";

my %dpkg_divert;
my $dpkg_divert = "dpkg-divert --list|";
open(DIVERT,"$dpkg_divert") 
    or die "Couldn't find the dpkg-divert command: $!\n";
while (<DIVERT>) {
    
    my($original,$diversion,$package) = (split(" "))[2,4,6];
    chomp $package;
    if (!$dpkg_divert{$package}) { # Just add to the array
	$dpkg_divert{$package} = [$original,$diversion];	
    }
    else {
	push @{ $dpkg_divert {$package} }, $original, $diversion;
    }

}
close(DIVERT) or die "Couldn't close: $!\n";

open(DIVERT,">$home_yard_replacements/var/lib/dpkg/diversions")
    or die "Couldn't open Replacements/var/lib/dpkg/diversions: $!\n";
my @info;
foreach my $rp (@required_packages) {
    $rp = (split(/_/,$rp))[0];
    # Get rid of the escapes from the previous invocation.
    $rp =~ s/\\//g if $rp =~ /\\+/g;

    my $count = 0; my @divert;
    if ($dpkg_divert{$rp}) {
            foreach my $dv ( @{ $dpkg_divert{$rp} } ) {
		push(@divert,$dv);
		if ($count == 1) {
		    print DIVERT "$divert[0]\n";
		    print DIVERT "$divert[1]\n";
		    print DIVERT "$rp\n";
		    $count = -1; undef @divert;
		}
		$count++;
            }
    }

    # Figure out info/*  .. this covers it for now.
    if (-f "$info/$rp.preinst") {
	push(@info,"$info/$rp.preinst\n");
    }
    if (-f "$info/$rp.postinst") {
	push(@info,"$info/$rp.postinst\n");        
    }
    if (-f "$info/$rp.prerm") {
	push(@info,"$info/$rp.prerm\n");        
    }
    if (-f "$info/$rp.postrm") {
	push(@info,"$info/$rp.postrm\n");        
    }
    if (-f "$info/$rp.list") {
	push(@info,"$info/$rp.list\n");        
    }
    if (-f "$info/$rp.shlibs") {
	push(@info,"$info/$rp.shlibs\n");        
    }
    if (-f "$info/$rp.conffiles") {
	push(@info,"$info/$rp.conffiles\n");        
    }
    if (-f "$info/$rp.md5sums") {
	push(@info,"$info/$rp.md5sums\n");        
    }
    if (-f "$info/$rp.config") {
	push(@info,"$info/$rp.config\n");        
    }
    if (-f "$info/$rp.templates") {
	push(@info,"$info/$rp.templates\n");        
    }

}
close(DIVERT);

return @info;

} # end sub status_info_divert

sub alternatives {

    my $ls = "ls -l /etc/alternatives|";
    my @ls;
    open(LS,$ls) or die "No ls?: $!\n";
    while (<LS>) {
	if (/->/) {
	    my($left,$right) = split(" -> ");
	    chomp $right; 
	    # Yard adds this stuff.
	    $right =~ s/\.\.\/\.\.//g; 

	    $left =~ s/^.*\d+\s//g;
	    if (!$alternatives{$right}) {
		$alternatives{$right} = [$left]; 
	    }
	    else {
		push @{ $alternatives {$right} }, $left;
	    }
	}
    }
    close(LS);

} # end sub alternatives

sub inetd_in {
    
    my $inetd = "/etc/inetd.conf";
    open(INETD,"$inetd") or return "Couldn't open /etc/inetd.conf: $!\n";
    # Basically will ignore anything with less than 7 columns, and
    # will comment lines where the executables don't exist.
    while (<INETD>) {
	if ( (split(/\s+/))[6] && !/^#.*/ ) {
	     my $seventh_column = (split(/\s+/))[6]; 
	     chomp $seventh_column;
	     $inetd{ basename($seventh_column) } = 0;
	 }
    }
    close(INETD);

}

sub inetd_out {

    my $inetd = "/etc/inetd.conf";
    open(REP_INETD,">$home_yard_replacements/etc/inetd.conf") 
	or return "Couldn't open Replacements/etc/inetd.conf: $!\n";
    open(INETD,"$inetd") or return "Couldn't open /etc/inetd.conf: $!\n";
    print REP_INETD "$main::Id\n";
    print REP_INETD "# GENERATED BY MAKE_DEBIAN\n\n";
    while (<INETD>) {
	if ( (split(/\s+/))[6] && !/^#.*/ ) {
	     my $seventh_column = (split(/\s+/))[6]; 
	     chomp $seventh_column;
	     if ( $inetd{ basename($seventh_column) } == 1 ) {
		 print REP_INETD $_;
	     }
	     else {
		 print REP_INETD "# $_";
	     }
	}
	else {
	    print REP_INETD $_;
	}
    }
    close(REP_INETD);
    close(INETD);

}

sub home_builder {

    my ($home_builder) = @_; 

    if (!-d $home_builder) {
	if (-e $home_builder) {
	    print "ERROR: A file exists where $home_builder should be.\n";
	}	
	else {
	    my @directory_parts = split(m,/,,$home_builder);
	    my $placement = "/";
	    for (1 .. $#directory_parts) {
		$_ == 1 ? ($placement = "/$directory_parts[$_]")
		    : ($placement = $placement . "/" . $directory_parts[$_]);
		-d $placement or mkdir $placement;
	    }
	}
    }

} # end home_builder

# The least important function,
# so therefore probably the most important function.
sub start_up {

    # existence of dpkg
    if (!-f "/usr/bin/dpkg") {
	die "You are not using a Debian system, in the future this " .
	   "may be supported, but for now you need living Debian.\n";
    }

    # Swim has never been installed before?
    my $dpkg_result = system "dpkg -l swim >/dev/null 2>&1";
    if ($dpkg_result != 0) {
	die "Dswim is required:\n\n" .
            "Add one of these lines to your /etc/apt/sources.list:\n" .
	    "deb http://prdownloads.sourceforge.net/avd ./  or\n" .
	    "deb http://download.sourceforge.net/avd ./\n\n" .
            "Then do `apt-get update` and `apt-get install dswim`\n" .
            "";
    }

    # Swim has been installed but is removed or purged
    my $dpkg_s = "dpkg -s dswim|";
    open(DPKG,"$dpkg_s") or die "Couldn't find dpkg: $!\n";
    while (<DPKG>) {
	if (/Status:/) {
	    if (!/\s+installed/) {
		if (/purge|deinstall/) {
		    die "Dswim needs to be reinstalled:\n\n" .
	       "Add one of these lines to your /etc/apt/sources.list:\n" .
	       "deb http://prdownloads.sourceforge.net/avd ./  or\n" .
	       "deb http://download.sourceforge.net/avd ./\n\n" .
	       "Then do `apt-get update` and `apt-get install dswim`\n" .
            "";
		}
	    }
	}
    }
    close(DPKG);

    # Swim is installed but the databases need to be initialized.
    my $swim = "swim -qf /sbin/init|";
    open(SWIM,$swim) or die "Had trouble using dswim: $!\n";
	while (<SWIM>) {
	    if ($_ eq "file init is not owned by any package\n") {
		my $db_reply = "nothing";
		print "It appears that dswim has never had its database " .
		    "generated.  Would you like me to do this for you? " .
			"[yes or no]: ";
		while (<STDIN>) {
		    $db_reply = $_;
		    last if $db_reply eq "yes\n";
		    last if $db_reply eq "no\n";
		    if ($db_reply ne "yes\n" || $db_reply  ne "no\n") { 
		print "It appears that dswim has never had its database " .
		    "generated.  Would you like me to do this for you? " .
			"[yes or no]: ";
		    }
		}
		system "swim --initdb" if $db_reply eq "yes\n";
		die "Sorry, can't continue until database is " .
		    "generated\n" if $db_reply eq "no\n";
	    }
	}
    close(SWIM);

    # Does file-rc exit?
    $dpkg_s = "dpkg -s file-rc|";
    open(DPKG,"$dpkg_s") or die "Couldn't find dpkg: $!\n";
    while (<DPKG>) {
	if (/Status:/) {
	    if (!/\s+installed/) {
	    die "The script requires that file-rc be installed. " .
		"Please install it first.\n";
	    }
	}
    }
    close(DPKG);

    if (!-d $home) {
	home_builder($template_dir);
	home_builder("$home_yard_replacements/etc");
    }

    # print "Everything is in order, but it never hurts to rebuild dswim " .
    # "with --rebuilddb\n";


} # end start_up