automated installations (5)

I wrote 2 scripts yesterday to unpack and repack the partman-auto_41.udeb package.
Being able to change the code allowed me to track down the bug much faster.

Next to the 2 scripts to unpack and pack this specific udeb, I also have 2 scripts to mount and umount the initrd (to change the preseed config file) and a s
cript to recreate the ISO.

These scripts are very specific to my environment, but if you want to have a look at them and modify them to your environment, go ahead :) I'll attach them t
o this post.

Now for the big news: I patched partman-auto so it works with preseed !
To be more precise: the bugs I found earlier were only a part of the problem. After I had changed the code to use the real free diskspace (instead of the cal
culated free space, rounded to MB) in the calculations, All 3 partitions were created nicely. However, partman-auto made the last partition a logical one ins
tead of a primary one. That made me take a closer look at the whole algorithm and I found out it ALWAYS creates an extended partition at the end of the disk.

Why ? In short because after creating all primary partitions, it think it will need to create even more partitions for some reason (that is the bug). It then
looks at the diskspace, decides it's not enough, then deletes the last partition and replaces it with an extended one. The last partition is then created ag
ain inside this extended partition.

Let's look at the original code and how I patched it:

100: while
101: [ "$free_type" = pri/log ] \
102: && echo $scheme | grep '\$primary{' >/dev/null
103: do
104: pull_primary
105: set -- $primary
106: open_dialog NEW_PARTITION primary $4 $free_space beginning ${1}000001
107: read_line num id size type fs path name
108: close_dialog
109: if [ -z "$id" ]; then
110: db_progress STOP
111: autopartitioning_failed
112: fi
113: neighbour=$(partition_after $id)
114: if [ "$neighbour" ]; then
115: open_dialog PARTITION_INFO $neighbour
116: read_line x1 new_free_space x2 new_free_type fs x3 x4
117: close_dialog
118: fi
119: if
120: [ -z "$neighbour" -o "$fs" != free \
121: -o "$new_free_type" = primary -o "$new_free_type" = unusable ]
122: then
123: open_dialog DELETE_PARTITION $id
124: close_dialog
125: open_dialog NEW_PARTITION primary $4 $free_space end ${1}000001
126: read_line num id size type fs path name
127: close_dialog
128: if [ -z "$id" ]; then
129: db_progress STOP
130: autopartitioning_failed
131: fi
132: neighbour=$(partition_before $id)
133: if [ "$neighbour" ]; then
134: open_dialog PARTITION_INFO $neighbour
135: read_line x1 new_free_space x2 new_free_type fs x3 x4
136: close_dialog
137: fi
138: if
139: [ -z "$neighbour" -o "$fs" != free -o "$new_free_type" = unusable ]
140: then
141: open_dialog DELETE_PARTITION $id
142: close_dialog
143: break
144: fi
145: fi
146: shift; shift; shift; shift
147: setup_partition $id $*
148: primary=''
149: scheme="$logical"
150: free_space=$new_free_space
151: free_type="$new_free_type"
152: done
153:
154: db_progress STEP 1
155:
156: foreach_partition '
157: if [ -z "$free_space" ]; then
158: db_progress STOP
159: autopartitioning_failed
160: fi
161: open_dialog PARTITION_INFO $free_space
162: read_line x1 free_space x2 free_type fs x3 x4
163: close_dialog
164: if [ "$fs" != free ]; then
165: free_type=unusable
166: fi
167: case "$free_type" in
168: primary|logical)
169: type="$free_type"
170: ;;
171: pri/log)
172: type=logical
173: ;;
174: unusable)
175: db_progress STOP
176: autopartitioning_failed
177: ;;
178: esac
179: if [ "$last" = yes ]; then
180: open_dialog NEW_PARTITION $type $4 $free_space full ${1}000001
181: else
182: open_dialog NEW_PARTITION $type $4 $free_space beginning ${1}000001
183: fi
184: read_line num id size type fs path name
185: close_dialog
186: if [ -z "$id" ]; then
187: db_progress STOP
188: autopartitioning_failed
189: fi
190: shift; shift; shift; shift
191: setup_partition $id $*
192: free_space=$(partition_after $id)'


This time I added nice linenumbers (grep -n "" file) ;)

The first while-loop (from 100-152) is where the primary partitions are created.
If you don't look at the code between line 120 and 144, the code seems pretty obvious: for every primary partition, create the partition. If there is not eno
ugh space, complain and exit.
The check that happens on 120-121 tests whether there is some free usable space left.
If the check is true (meaning there is no space left), then the script REMOVES the last partition and creates a new extended partition.
But this check WILL fail when 3 primary partitions are created, because no space will be left after that.

I patched the code in a number of different ways. First, instead of relying on the calculated free diskspace, I recalculate the real free disk space after ea
ch partition is added. Next, when a partition wants to be created that is too big for the amount of free diskspace, I trim it down to the available free disk
space. Last but not least, Instead of assuming that there has to be free diskspace left after adding each primary partition, I check whether we need to creat
e any extra partitions at all. If not, then we don't need any free diskspace and the entire check is skipped.

I attached the patch to this post too.

I will once again report my findings to the debian-boot list and also to bugs.debian.org.

Now that the partition scheme is OK, I want to ask the user for a hostname for the machine.
The debconf variable "netcfg/get_hostname" is what I'm looking for, but I can't seem to get debian-installer to ask me that question. Setting it to some valu
e works, as well as letting DHCP set it.
But debian-installer never asks the question and assumes the default hostname "debian" if no other is picked.
The netcfg udeb contains no .config file and the only real executable I can find in there is the program "/bin/netcfg" which is a binary. Patching the source
is something I want to avoid.
The reason why the question is not asked is probably because the priority is too low (I'm using priority "critical" in preseed)

I'm considering asking the question in some custom config script and maybe setting it myself. Before I can do that I need to know where the hostname is used
so that I can reverse whatever debian-installer does with the hostname it picks.
I've installed debian with the hostname and networkname "xyz123abc". Much to my surprise, this hostname is not used. Instead, the reverse DNS "dhcp-119" is u
sed (and I'm not even using DHCP, just the IP address)

Anyway, grepping for "dhcp-119" in all files results in the following list:

/etc/hostname
/etc/hosts
/etc/motd
/etc/exim4/update-exim4.conf.conf
/etc/ssh/ssh_host_rsa_key.pub
/etc/ssh/ssh_host_dsa_key.pub
/etc/mailname
/var/lib/exim4/config.autogenerated
/var/cache/debconf/config.dat
/var/cache/debconf/config.dat-old
/var/log/exim4/mainlog
/var/log/syslog
/var/log/auth.log
/var/log/debian-installer/cdebconf/questions.dat
/var/log/daemon.log
/var/log/kern.log
/var/log/lpr.log
/var/log/debug
/var/log/messages
/var/spool/mail/mail
/var/mail/mail


In /var/cache/debconf/config.dat (where the answers to the debconf questions are stored), I find that there is also a variable base-config/get-hostname (mind
the "-" instead of "_")
This doesn't do the trick either... Debian insists on calling my machine "dhcp-119".

The hostname seems to be set in the base-config udeb. There is also a baseconfig-udeb udeb, which appears to be the second stage installer.

This code is probably the culprit (from base-config udeb /usr/lib/base-config/menu/hostname)

if [ -z "$currname" ] || [ "$currname" = localhost ]; then
# Check IP addresses of interfaces, try to look up
# using DNS, use that name as default hostname, and
# ask medium priority question if there is a
# default, and high priority question if the default
# is empty.
priority=high

# Make sure there is some good default. Only change
# the default value, to make it possible to override
# this using the debconf database.
db_set base-config/get-hostname $defaultname
set_default_from_dns
else
# Ask at medium priority so the menu item does something if
# manaully selected.
priority=medium
db_set base-config/get-hostname $currname
fi