#!/usr/bin/perl # http://www.phys.ethz.ch/~franklin/Projects/dphys2/debconf-preload # - preload debconf database, so that base-config does not ask questions # copyright ETH Zuerich Physics Deparement, use under either BSD or GPL license # author Neil Franklin, last modification 2002.12.18 # this script is run at the end of first installation stage, before reboot # and so lets us preload debconf, with fake entries, to silence base-config # this script is run by the command /usr/sbin/chroot /target /debconf-preload # so all paths should be relative to the targets / directory # --- setup some variables for better code legibility $debconfdb = "%DEBCONF_DB%"; # --- save the old database, for referrence, and as base for modifying rename($debconfdb, $debconfdb . ".orig"); # and generate new database, reading old, modifying it, write out # we handle our own filenames, as they are constant, no need for stdin/stout # this keeps all details here in script, not some out in dbootstrap open(DBORIG, "<$debconfdb" . ".orig"); open(DBMOD, ">$debconfdb"); # we want to read entie blank line separated blocks $/ = ""; while () { # blocks have Name: something as their first line /^Name: ([^\n]*)\n/; # --- process to set up, for each of the /usr/lib/base-config/* scripts # these sections are labled after their /usr/lib/base-config/* scripts # - 00dbootstrap_settings - harmless, needed # just set debconf system to only ask critical stuff, minimize questions #if ($1 eq "debconf/priority") { # s@Value: medium@Value: critical@; } # or better, tell it to shut up all together # and then we "just" need to fudge/patch up the data base for our settings # ** this does not work, it asks questions anyway, even "medium" level ones #if ($1 eq "debconf/frontend") { # s@Value: Dialog@Value: Noninteractive@; } # - 10intro - annoying text output, totally useless # is "medium", will be killed anyway by "critical", but be consistent if ($1 eq "base-config/intro") { s@Owners:@Value: \nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # - 12console-tools - harmless, needed # no questions, definitely no changes # - 15tzconfig - asks questions, but we need to give time zone info if ($1 eq "tzconfig/gmt") { # insert "Value:" before "Owners:" s@Owners:@Value: true\nOwners:@; # tag these onto the end s@\n\n@\nFlags: seen\n\n@; # use fields 1-6 (not 1-5) here, because day may be 1 digit, 2 spaces # after year there are 2 spaces, so this works, tzsetup does it so also $timestring = `/sbin/hwclock --show | cut -f 1-6 -d " "`; s@\n\n@\nVariables:\n hwtime = $timestring\n\n@; # /usr/sbin/tzsetup tries everything it can do, to get its dialog up # even faking "seen false" debconf entries, them bastards!!! :-) # so we patch the script to not do this, and then restore itsself # thanks to Debian we need to fix this multiple places, so sub it &delete_script_line("/usr/sbin/tzsetup", "seen false"); } if ($1 eq "tzconfig/change_timezone") { s@\n\n@\nVariables:\n timezone = UTC\n\n@; } if ($1 eq "tzconfig/geographic_area") { s@Owners:@Value: %CONF_TIMEZOME_AREA%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } if ($1 eq "tzconfig/select_zone") { # add tzconfig/select_zone/%CONF_TIMEZOME_AREA% to our DB # dump the actual tzconfig/select_zone record # as the normal print will do tzconfig/select_zone/%CONF_TIMEZOME_AREA% print DBMOD; # add the entire new block tzconfig/select_zone/%CONF_TIMEZOME_AREA% # will be added to output by the normal print $_ = "Name: tzconfig/select_zone/%CONF_TIMEZOME_AREA%\n" . "Template: tzconfig/select_zone\n" . "Value: %CONF_TIMEZOME_PLACE%\n" . "Owners: \n" . "Flags: seen\n" . "Variables:\n" . " choices = %CONF_TIMEZOME_PLACE%\n\n"; } # - 20passwd - asks questions, but we need to set root password, no make user # there are no pre-existing entries for passwd/* in the debconf DB (!) # so look for last entry before passwd/* (netkit-inetd/inetd-dos-services) if ($1 eq "netkit-inetd/inetd-dos-services") { # force it out and then output all passwd/* until the last one # dump the netkit-inetd/inetd-dos-services before $_ overwrite print DBMOD; # attempts to do this by just fudging data into debconf have failled # even putting data in, and setting "Flags: seen", # and setting priority to critical, and setting noninteractive # the script just keeps on asking for these # unfortunately the settings are ignored somewhere inside debconf # seems that either debconf is broken, or dpkg-reconfigure sabotaging # so in addition to setting we also kill the call to dpkg-reconfigure # and do the desired work it did do ourselves # copying the desited stuff from /var/lib/dpkg/info/passwd.config # fix up system so that dpkg-reconfigure is not run from 20passwd &delete_script_line("/usr/lib/base-config/20passwd", "dpkg-reconfigure"); # set up our passwd/* records # we do not install an user account, so don't do anything $_ = "Name: passwd/make-user\n" . "Template: passwd/make-user\n" . "Value: false\n" . "Owners: passwd\n" . "Flags: seen\n\n"; print DBMOD; # enable MD5 passwords, if wanted $_ = "Name: passwd/md5\n" . "Template: passwd/md5\n" . "Value: %CONF_PASSWORD_MD5%\n" . "Owners: passwd\n" . "Flags: seen\n\n"; print DBMOD; # this seems to be all that actually is done to the system if ("%CONF_PASSWORD_MD5%" eq true) { extend_file_line("/etc/pam.d/passwd", "^password", " md5"); extend_file_line("/etc/pam.d/login", "^password", " md5"); } # set our desired root password, debconf with empty Value: lines $_ = "Name: passwd/password-empty\n" . "Template: passwd/password-empty\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/password-mismatch\n" . "Template: passwd/password-mismatch\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/root-password\n" . "Template: passwd/root-password\n" . "Value: \n" . "Owners: passwd\n" . "Flags: seen\n\n"; print DBMOD; $_ = "Name: passwd/root-password-again\n" . "Template: passwd/root-password-again\n" . "Value: \n" . "Owners: passwd\n" . "Flags: seen\n\n"; print DBMOD; # and then crypt the actual wanted password into /etc/passwd if (%CONF_PASSWORD_MD5% eq true) { # user wants MD5 password, so we need to encryt the password ourself # we use the salt algorithm from /var/lib/dpkg/info/passwd.config $salt = "\$1\$"; @base64 = split(//, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"); open (URANDOM, "/dev/null"); } # we do not install an user account, so we miss these also $_ = "Name: passwd/user-fullname\n" . "Template: passwd/user-fullname\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/user-password\n" . "Template: passwd/user-password\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/user-password-again\n" . "Template: passwd/user-password-again\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/username\n" . "Template: passwd/username\n" . "Owners: passwd\n\n"; print DBMOD; $_ = "Name: passwd/username-bad\n" . "Template: passwd/username-bad\n" . "Owners: passwd\n\n"; # last will be printed by the normal print at the bottom, no print DBMOD; ; } # - 25pcmcia - asks questions, but we need to give "delete" into the DB if ($1 eq "base-config/remove-pcmcia") { s@Owners:@Value: %CONF_PCMCIA_REMOVE%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # - 30pon - asks stuff, is PPP and we are on Ethernet, so useless # is "critical", so even priority can not kill these, needs DB modification if ($1 eq "base-config/use-ppp") { s@Owners:@Value: false\nOwners:@; s@\n\n@\nFlags: seen\n\n@; # /usr/lib/base-config/30pon is annother DB faking "seen false" assh* # repeat the same "patch the script" method as in tzsetup &delete_script_line("/usr/lib/base-config/30pon", "seen false"); } # - 40apt-setup - asks questions, but we need to give details into DB # *** fixme *** - this still asks questions # we want explicit woody, not stable, so no surprise upgrades later on if ($1 eq "apt-setup/distribution") { s@Owners:@Value: woody\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # setup where everything comes from # we fetch everything by HTTP, as it is universally available if ($1 eq "apt-setup/uri_type") { s@Owners:@Value: http\nOwners:@; s@\n\n@\nFlags: seen\n\n@; s@\n\n@\nVariables:\n note = \n\n@; } # this is most likely useless, but set same as test install if ($1 eq "apt-setup/country") { s@Owners:@Value: enter information manually\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # our server if ($1 eq "apt-setup/hostname") { s@Owners:@Value: %CONF_DEBSERVER%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # where it is on our server if ($1 eq "apt-setup/directory") { s@Owners:@Value: /%CONF_DEBDIR%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # no proxy as we are on the same network if ($1 eq "apt-setup/http_proxy") { s@Owners:@Value: \nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # setup what our package policies are # do we use contrib stuff here if ($1 eq "apt-setup/contrib") { s@Owners:@Value: %CONF_USE_CONTRIB%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # do we use non-free stuff here if ($1 eq "apt-setup/non-free") { s@Owners:@Value: %CONF_USE_NON_FREE%\nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # setup what servers we want to use, apart from the main one # are we outside the United States of Idiotic Politicians if ($1 eq "apt-setup/non-us") { if ("x%CONF_DEBSERVER_NON_US%" ne x and "x%CONF_DEBDIR_NON_US%" ne x) { s@Owners:@Value: true\nOwners:@; } else { s@Owners:@Value: false\nOwners:@; } s@\n\n@\nFlags: seen\n\n@; } # do we want it secure if ($1 eq "apt-setup/security-updates") { if ("x%CONF_DEBSERVER_SECURITY%" ne x and "x%CONF_DEBDIR_SECURITY%" ne x) { s@Owners:@Value: true\nOwners:@; } else { s@Owners:@Value: false\nOwners:@; } s@\n\n@\nFlags: seen\n\n@; } # no more apt servers, thats it folks! if ($1 eq "apt-setup/another") { s@Owners:@Value: false\nOwners:@; s@\n\n@\nFlags: seen\n\n@; # and now get the system to actually do what we want # don't run all the dialogs, this is the easiest way, no action &delete_script_line("/usr/lib/base-config/40apt-setup", "apt-setup probe"); # generate our desired /etc/apt/sources.list file # what types of packages we want to have $type = "main"; if (%CONF_USE_CONTRIB% eq true) { $type .= " contrib"; } if (%CONF_USE_NON_FREE% eq true) { $type .= " non-free"; } open(EASL, "> /etc/apt/sources.list"); # we allways add our install server we got the base install from print EASL "deb http://%CONF_DEBSERVER%/%CONF_DEBDIR% woody $type\n"; print EASL "deb-src http://%CONF_DEBSERVER%/%CONF_DEBDIR% woody $type\n"; # and then add non-US, security and local package servers if given if ("x%CONF_DEBSERVER_NON_US%" ne x and "x%CONF_DEBDIR_NON_US%" ne x) { print EASL "deb http://%CONF_DEBSERVER_NON_US%/" . "%CONF_DEBDIR_NON_US% woody/%CONF_DEBSUBDIR_NON_US% $type\n"; print EASL "deb-src http://%CONF_DEBSERVER_NON_US%/" . "%CONF_DEBDIR_NON_US% woody/%CONF_DEBSUBDIR_NON_US% $type\n"; } if ("x%CONF_DEBSERVER_SECURITY%" ne x and "x%CONF_DEBDIR_SECURITY%" ne x) { print EASL "deb http://%CONF_DEBSERVER_SECURITY%/" . "%CONF_DEBDIR_SECURITY% woody/%CONF_DEBSUBDIR_SECURITY% $type\n"; print EASL "deb-src http://%CONF_DEBSERVER_SECURITY%/" . "%CONF_DEBDIR_SECURITY% woody/%CONF_DEBSUBDIR_SECURITY% $type\n"; } if ("x%CONF_DEBSERVER_LOCAL%" ne x and "x%CONF_DEBDIR_LOCAL%" ne x) { print EASL "deb http://%CONF_DEBSERVER_LOCAL%/" . "%CONF_DEBDIR_LOCAL% woody/%CONF_DEBSUBDIR_LOCAL% $type\n"; print EASL "deb-src http://%CONF_DEBSERVER_LOCAL%/" . "%CONF_DEBDIR_LOCAL% woody/%CONF_DEBSUBDIR_LOCAL% $type\n"; } close(EASL); # our just generated host lines get commented out # by the "comment out the shipped sources.list" code in 40apt-setup # so undo this, as we are using our "shipped" sources.list open(ULBC40AS, ">>/usr/lib/base-config/40apt-setup"); print ULBC40AS "mv /etc/apt/sources.list /\n"; # this strips first char of # by taking all after first # print ULBC40AS "cut -f 2- -d '#' /sources.list > /etc/apt/sources.list\n"; # and while this is open, add the lost apt-get update from apt-setup # the || true is needed, so that apt-get with non-accessibe http: # does not end up returning 100 to base-config, endless looping by init # an simple exit 0 after the apt-get fails because script has set -e print ULBC40AS "apt-get update || true\n"; close(ULBC40AS); } # - 50tasksel and 60dselect - interactive installers # we don't use them, we apt-get install all the stuff we want # anyone else can also call these from the command line if they want them # are both medium, but little work to knock them out anyway if ($1 eq "base-config/run-tasksel") { s@Owners:@Value: false\nOwners:@; s@\n\n@\nFlags: seen\n\n@; # is yet annother DB "seen false" faker, again "patch the script" &delete_script_line("/usr/lib/base-config/50tasksel", "seen false"); } if ($1 eq "base-config/run-dselect") { s@Owners:@Value: false\nOwners:@; s@\n\n@\nFlags: seen\n\n@; # is yet annother DB "seen false" faker, again "patch the script" &delete_script_line("/usr/lib/base-config/60dselect", "seen false"); } # - 75apt-get - asks questions, but we just want the to be ignored # asks 3 non-dialog questions, these are hard coded, not debconf at all(!) # there are no pre-existing or new entries entries in the debconf DB # so look for last entry in apt-setup (apt-setup/uri_type) if ($1 eq "apt-setup/uri_type") { # we do all this inline, as we need an special "dual line replace" edit local($inst, $instline); $inst = "/usr/lib/dpkg/methods/apt/install"; # save old install for reactivating later rename($inst, $inst . ".orig"); open(INSTORIG, "<$inst" . ".orig"); open(INSTMOD, ">$inst"); # replace lines with $reppattern, only lines and not blocks, so re-set $/ $/ = "\n"; while ($instline = ) { # force erasing of .debs, don't bother asking if ($instline =~ /Do you want to erase any previously downloaded/) { $instline = "if [ true ]; then\n"; } # don't ask stupid "enter" confirmation, as no answer is taken anyway # as this exits, put in command to reactivate unchanged install here if ($instline =~ /Press enter to continue/) { $instline = "mv " . $inst . ".orig " . $inst . " && exit;\n"; } # stop apt-get dselect-upgrade asking for confirmations # for this pipe an endless supply of "y" into it if ($instline =~ /dselect-upgrade/) { $instline = "yes | " . $instline; } print INSTMOD $instline; } $/ = ""; close(INSTORIG); close(INSTMOD); # and make our replacement install executable chmod(0755, $inst); } # - 77exim - unused mailer, we later install our preferred mailer # does not use debconf, will need its own personal invitation to shut up # best is to make /usr/sbin/eximconfig non executable, 77exim jumps it then # exim has no debconf database records, so trigger it off of an unrelated one # I have chosen one that is somehow appropriate :-) if ($1 eq "base-config/install-problem") { chmod(0644, "/usr/sbin/eximconfig"); } # - 80poff - asks stuff, tidy up from 30pon stuff # this seems to not get asked anyway, if 30pon was negative # - 90final-messages - annoying text output, totally useless # is "medium", will be killed anyway by "critical", but be consistent if ($1 eq "base-config/login-with-tty") { s@Owners:@Value: \nOwners:@; s@\n\n@\nFlags: seen\n\n@; } # - 98s390 - harmless, but actually irrelevant # no questions, definitely no changes # - 99inittab - harmless, needed # no questions, definitely no changes # - and output the block, modified or not print DBMOD; } # and tidy up files close(DBORIG); close(DBMOD); # patch an shell script, deleting any line containing $delpattern sub delete_script_line { local($script, $delpattern) = @_; local($scriptline); # save old script for reactivating later rename($script, $script . ".orig"); # ensure that these are not runnable, else /usr/sbin/base-config screws us up chmod(0644, $script . ".orig"); open(SCRIPTORIG, "<$script" . ".orig"); open(SCRIPTMOD, ">$script"); # kill lines with $delpattern, only lines and not blocks, so re-set $/ $/ = "\n"; while ($scriptline = ) { unless ($scriptline =~ /$delpattern/) { print SCRIPTMOD $scriptline; } } $/ = ""; # add tail command to reactivate unchanged script after running changed one print SCRIPTMOD "mv " . $script . ".orig " . $script . "\n"; # and don't forget to make the reactivated script runnable again print SCRIPTMOD "chmod 755 " . $script . "\n"; close(SCRIPTORIG); close(SCRIPTMOD); # and make our replacement script executable chmod(0755, $script); } # extend line in an config file, modifying any line containing $modpattern sub extend_file_line { local($file, $modpattern, $extension) = @_; local($fileline); # save old file for archival rename($file, $file . ".orig"); open(FILEORIG, "<$file" . ".orig"); open(FILEMOD, ">$file"); # extend lines with $modpattern, only lines and not blocks, so re-set $/ $/ = "\n"; while ($fileline = ) { $fileline =~ s/^(.*$modpattern.*)$/$1$extension/; print FILEMOD $fileline; } $/ = ""; close(FILEORIG); close(FILEMOD); }