#!/usr/bin/perl -w # make_debian-X11 Copyright (C) 2001 from gBootRoot # Lead Developer and Project Coordinator # Jonathan Rosenbaum # # 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. use strict; use File::Basename; # You will need to get swim 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-X11.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. my $version = "1.0"; # 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 swim 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 binutils bzip2 file libbz2-1.0 libfreetype6 libglib1.2 libgtk-perl libgtk1.2 make xfonts-base xfree86-common xlibmesa3 xlibs xserver-common xterm xutils zlib1g libgdbmg1 libxaw7 gbootroot flwm libfltk1 xnest make-debian-x11 ash); # NEXT EDIT TEMPLATE # Before starting make sure swim and file-rc are present. start_up(); 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 = ; chomp @required_packages; close(SWIM); # All the files open(SWIM,$swim_list) or die "Couldn't open swim_list: $!\n"; my @required_files = ; chomp @required_files; close(SWIM); open(SWIM,$extra_files) or die "Couldn't open extra_files: $!\n"; my @extra_files = ; chomp @extra_files; close(SWIM); push(@required_files,@extra_files); ################################################################# ################################################################# # # EDIT # BELOW # # Edit below $stuff = << "STUFF" to make changes to the template. sub stuff { my $stuff = << "STUFF"; # Generated by make_debian-X11. # This template creates a complete Debian system which is more streamlined # than the base.tgz used for normal installations with the addition of X11. # 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 # swim 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. Look at /tmp/gbootroot_tmp'time-date'/verbose instead. # # The windows will appear to freeze up while using this template, this is # natural, be patient, because it will complete. If you want to create # another filesystem concurrently, open up another invocation of gBootRoot. # 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_debian-X11 # made by make_debian-X11 /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_debian-X11 /var/lib/dpkg/cmethopt /var/lib/dpkg/lock /var/lib/dpkg/status <= Replacements/var/lib/dpkg/status_debian-X11 /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_debian-X11 # Tcpd stuff /etc/hosts.allow /etc/hosts.deny # Network stuff # You will want to edit the interfaces file. # Remember to load any needed modules on the host system, for instance # if tap is used, you will want to do this: # modprobe ethertap # modprobe netlink_dev # 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 # X stuff /usr/X11R6/bin/xsetroot /usr/X11R6/bin/startx <= Replacements/usr/X11R6/bin/startx-debian-X11 /root/README <= Replacements/root/README-debian-X11 /usr/bin/X11 -> ../X11R6/bin /usr/include/X11 -> ../X11R6/include/X11 /usr/lib/X11 -> ../X11R6/lib/X11 /usr/X11R6/lib/X11/rgb.txt -> /etc/X11/rgb.txt /usr/bin/X11/xsetroot /usr/X11R6/lib/X11/xserver -> /etc/X11/xserver /etc/X11/Xwrapper.config /etc/X11/xkb/xkbcomp -> /usr/X11R6/bin/xkbcomp /usr/X11R6/bin/xkbcomp # Administrative stuff /root/make_swapfile <= Replacements/root/make_swapfile /root/setup <= Replacements/root/setup-debian-X11 /root/README <= Replacements/root/README-debian-X11 # Devices - optional stuff which can be picked up by devfsd. /dev/MAKEDEV # a link /dev/mem /dev/kmem /dev/null /dev/zero /dev/ram* /dev/console /dev/tty[0-9] /dev/hd[abcd]* /dev/ttyS[0-9] /dev/fd0* /dev/sd* #/dev/cdrom #/dev/modem /dev/pts* /dev/ptmx /dev/initctl /dev/urandom /dev/ubd0 <= Replacements/dev/ubd0 # Empty directories with no stuff. /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 ## 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 ################################################################# ################################################################# ################### ## 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 $required_packages_check = "swim -q @required_packages|"; open (CHECK,$required_packages_check) or die "Couldn't find any required packages: $?\n"; my @rpc; while () { if (/^package/) { my $rpc = (split(/\s/))[1]; push(@rpc,$rpc); } } close (CHECK); 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 $extra_packages_check = "swim -q @extra_packages|"; open (CHECK,$extra_packages_check) or die "Couldn't find any required packages: $?\n"; my @epc; while () { if (/^package/) { my $epc = (split(/\s/))[1]; push(@epc,$epc); } } close (CHECK); 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"; # spooked myself #print STDERR "[If any of the package(s) below are already installed\n"; #print STDERR " run 'swim --rebuilddb' and run make_debian-X11 again.]\n\n"; print STDERR @epc , "\n\n"; $, = ""; } push(@required_packages,@extra_packages); ####################### ## Template Creation ## ####################### # Ask some questions first. my $doc_reply = "nothing"; print STDERR "The default is to remove /usr/share/{doc,man,info}? [yes or no]: "; while () { $doc_reply = $_; print $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 STDERR "\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 () { $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]: "; } } 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 = ; 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); system "chmod 444 $template_dir/$debian_yard"; # A good idea print STDERR "\nAll finished 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_debian-X11") or die "Couldn't open $home_yard_replacements/etc/runlevel.conf_debian-X11: $!\n"; my @sortedrc = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map { [ (split(/\s/,$_))[0], $_ ] } @file_rc; 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_debian-X11") or die "Couldn't open Replacements/var/lib/dpkg/status_debian-X11: $!\n"; while () { # 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$/) { # For debian packaging if ($rp eq "make-debian-x11") { if ($stat =~ /unpacked/) { $stat =~ s/unpacked/installed/; } print NEW_STATUS $stat; } else { 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 () { 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_debian-X11") or die "Couldn't open Replacements/var/lib/dpkg/diversions_debian-X11: $!\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 () { 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 () { 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_debian-X11") or return "Couldn't open Replacements/etc/inetd.conf_debian-X11: $!\n"; open(INETD,"$inetd") or return "Couldn't open /etc/inetd.conf: $!\n"; while () { 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); } # -------------------------------------------------------------------- # Jonathan's personal directions # This creates a X11 filesystem. # These replacements are unique and not found in CVS: # add sources.list to this, too. #/usr/X11R6/bin/startx <= Replacements/usr/X11R6/bin/startx-debian-X11 #/root/README <= Replacements/root/README-debian-X11 #/root/make_swapfile <= Replacements/root/make_swapfile #/root/umlnet <= Replacements/root/umlnet .. won't use. #/etc/apt/sources.list <= Replacements/etc/sources.list .. for adm. # setup script does this # 0. run dpkg-reconfigure for xfree86-common and xserver-common. # This catches mistakes. # 1. dpkg-reconfigure for xfonts-base # 2. make permissions correct for directory /home/user and all files * & .*. # 3. run swim --initdb .. this is done by make-debian-x11. # 4. run /etc/cron.daily/find # ................................................................... # debian_x11 sourceforge release preparation # 5. Other packages may be installed with apt-get. # 6. If any of these things were used: Clean out sources.list, # /var/cache/archives /var/lib/apt/lists, /etc/network/interface # should be commented in again. # 7. remove linux uml_* or just leave them. # 8. run /etc/cron.daily/sysklogd & /etc/cron.weekly/sysklogd # and clean out *.0, and dmesg if it needs it. # 9. halt and mount filesystem on loop and remove .bash_history if you # want to. # 10. test again. # -------------------------------------------------------------------- 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 "Swim 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 swim`\n" . ""; } # Swim has been installed but is removed or purged my $dpkg_s = "dpkg -s swim|"; open(DPKG,"$dpkg_s") or die "Couldn't find dpkg: $!\n"; while () { if (/Status:/) { if (!/\s+installed/) { if (/purge|deinstall/) { die "Swim 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 swim`\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 swim: $!\n"; while () { if ($_ eq "file init is not owned by any package\n") { my $db_reply = "nothing"; print STDERR "It appears that swim has never had its database " . "generated. Would you like me to do this for you? " . "[yes or no]: "; while () { $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 swim 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 () { 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 STDERR "Everything is in order, but it never hurts to rebuild swim " . "with --rebuilddb if you haven't done it in awhile\n"; } # end start_up