melux: a custom ubuntu iso creation script!

April 18, 2009

When I was working for the Greek Linux Format, I was making special editions of Ubuntu for the magazine’s DVD. Those were the same distro of course, but with a lot more packages preinstalled. For that purpose, I had written all the useful info and relevant commands inside a text file. Of course, that wasn’t highly efficient, since I had to manually run through (read: copy/paste) all the commands again and again for every new custom Ubuntu image. So, I was always thinking that I should assemble and automate all those commands in a nice Bash script, but I never really tried it. This week, I finally decided to build that script and share it with everyone. So, I hereby give you Melux 1.0 (see full code below).

Melux is a Bash script which automates the creation of custom Ubuntu ISO images. It does nearly everything you would ever need to do: creates necessary working directories, mount-loops the original ubuntu iso, copies its contents, mount-loops the squashfs file, copies its contents in a new dir and chroots in it where it modifies sources.lists and resolv.conf so that the chroot system is usable, and then presents a nice menu for the user to select which package groups to add. By default, these are my favorite packages for math, multimedia and development, but you can easily modify lines 24-39 to specify your packages.

Finally, melux creates the new squashfs file, updates all manifest files, and then creates your new custom Ubuntu iso. All these in under 400 lines of code, with full-blown ANSI colors (just for all times sake!), with minimal user interaction. The only three things the user (that’s you!) needs to specify are: the base work dir (where you must have copied the original Ubuntu iso), the ubuntu release (which must be the same release you run on, of course), and the custom iso filename.

Update: Of course, your running Ubuntu system should be connected to the Internet or else melux won’t be able to download and install the extra packages to your custom Ubuntu Live CD/DVD system. Note also that melux by default adds complete Greek language support and removes other languages. You can disable that by commenting out line 308.

Here’s a screenshot of melux running:

melux custom ubuntu iso creation script in action!

melux custom ubuntu iso creation script in action!

And this is the melux.sh code (download and chmod +x it before execution). Please use the git repository to view/download it:

#!/bin/bash
 
VERSION=1.0;
#  **********************************
# * 		melux 1.0	     *
# *  ubuntu iso customization script *
# *			  	     *
# *   Copyright: Dimitris Kalamaras  *
# *   Free to use under GPL3 licence *
# *     http://dimitris.apeiro.gr    *
#  **********************************
 
loop='./loop/';
work='./work/';
squash='./work/casper/filesystem.squashfs';  # DON'T CHANGE THIS!
new_squash_dir='./squashdir/';
 
# STEP 1: SPECIFY PACKAGES TO ADD HERE! (hint: use synaptic to find more packages and apt-cache rdepends to see what depends on them)
 
build_packages='build-essential';
desktop_packages='vlc ttf-liberation ktorrent inkscape scummvm njam';
mce_packages='elisa';
 
# WARNING: dont try to install....
#	wine or squid; those depend on samba winbind which needs /proc...
#       virtualbox-ose;  it needs kernel module so...
#	bootchart; depends on bootchart-java, so dont install it...
#	flashplugin-nonfree; it cannot be redistributed.
 
multimedia_packages='gstreamer0.10-plugins-ugly gstreamer0.10-plugins-ugly-multiverse  gstreamer0.10-plugins-bad gstreamer0.10-plugins-bad-multiverse gstreamer0.10-ffmpeg libavcodec-unstripped-52 gstreamer0.10-pitfdll libdvdread4 ffmpeg ffmpeg2theora';
math_packages='octave3.0 kig ygraph qtoctave wxmaxima lybniz';
devel_packages='libqt4-assistant libqt4-gui qt4-doc-html qt4-qtconfig qt4-demos libqt4-webkit libqt4-dev qt4-designer qdevelop vim subversion bzr mc';
greek_packages='language-support-el language-pack-el myspell-dictionary-el language-pack-gnome-el';
kde_packages='kubuntu-desktop';
download_packages='virtualbox-ose wine squid bootchart flashplugin-nonfree unrar';
 
#
# THAT'S ALL. JUST RELAX WHILE WE ARE MAKING YOUR CUSTOM UBUNTU ISO!!!
#
 
red='\E[1;31m';
green='\E[1;32m';
black='\E[1;37;38m';
white='e[1;37m';
normal='tput sgr0';
 
choose_packages() {
	echo    -e $black'Press 1-9 to choose packages or press 0 to continue...';$normal;
	echo -n -e $red'1.'; echo -e $black ' Build        ...';$normal;
	echo -n -e $red'2.'; echo -e $black ' Desktop      ...';$normal;
	echo -n -e $red'3.'; echo -e $black ' Development  ...';$normal;
	echo -n -e $red'4.'; echo -e $black ' Multimedia   ...';$normal;
	echo -n -e $red'5.'; echo -e $black ' Mathematics  ...';$normal;
        echo -n -e $red'6.'; echo -e $black ' Media center ...';$normal;
	echo -n -e $red'7.'; echo -e $black ' KDE desktop  ...';$normal;
        echo -n -e $red'9.'; echo -e $black ' All          ...';$normal;
	echo -n -e $red'0.'; echo -e $black ' DONE!        ...';$normal;
	echo -n -e $red'> '; $normal;
	read answer;
	return $answer;
}
 
echo    -e $red '  **********************************';
echo -n -e $red ' * ';$normal;echo -n "           melux $VERSION            ";echo -e $red '*';
echo -n -e $red ' * ';$normal;echo -n 'ubuntu iso customization script ';echo -e $red '*';
echo -n -e $red ' * ';$normal;echo -n ' copyright: Dimitris Kalamaras  ';echo -e $red '*';
echo -n -e $red ' * ';$normal;echo -n ' free to use under GPL3 licence ';echo -e $red '*';
echo -n -e $red ' * ';$normal;echo -n '   http://dimitris.apeiro.gr    ';echo -e $red '*';
echo    -e $red '  **********************************';
 
echo -n -e $black'checking mksquashfs   ...'; $normal;
if [ -f /usr/bin/mksquashfs ]; then
	echo -e $green 'OK'; $normal;
 
else
	echo -e $red 'mksquashfs not found! Installing package...';
	sudo apt-get install squashfs-tools
fi
 
echo -n -e $black'unmounting old mounts ...'; $normal;
mounted=`mount | grep $new_squash_dir | awk '{ print $3 }' `;
for i in $mounted; do
        sudo umount $i;
done
echo -e $green 'OK'; $normal;
 
echo    -e $black'enter new base dir    ...' $red 'this is where the original iso should be!'; $normal;
read dir;
 
echo    -e $black'entering base dir     ...' $dir; $normal;
cd $dir;
 
echo    -e $black'enter ubuntu release  ...' $red 'i.e. jaunty  (sould be the same version you run now!)'; $normal;
read release;
 
echo    -e $black'enter new iso name    ...' $red 'i.e. newubuntu-i386 (without .iso)'; $normal;
read newubuntu;
 
echo -n -e $black'preparing sources.list...'; $normal;
 
echo "deb http://security.ubuntu.com/ubuntu $release-security main restricted" > ./sources.list
echo "deb http://archive.ubuntu.com/ubuntu $release-updates main restricted" >> ./sources.list;
echo "deb http://archive.ubuntu.com/ubuntu/ $release  main restricted universe multiverse" >> ./sources.list
sleep 1;
echo -e $green 'OK'; $normal;
 
echo -n -e $black'checking loop dir     ...'; $normal;
sleep 1;
if [ -d $loop ]; then
	echo -e $green 'OK'; $normal;
	sudo umount $loop &> /dev/null;
else
	echo -e $red 'creating dir'; $normal;
	mkdir $loop;
fi
 
orig=`ls *.iso | grep ubuntu-`;
echo -n -e $black'mounting original iso ...';
sleep 1;
if [ -f $orig ]; then
	sudo mount -o loop $orig $loop
        echo -e $green 'OK';
else
        echo -e $red 'iso not found!';
	echo -e $black'bye!';
	exit;
fi
 
echo -n -e $black'checking working dir  ...';
sleep 1;
if [ -d $work ]; then
        #sudo rm -rf $work;
        size=`sudo du -h -s  $work  | awk '{print $1}'`;
        echo -e $green 'OK. Warning: work dir exists. Contents: ' $size;
else
        echo -e $red 'creating work dir';
        mkdir $work;
fi
 
echo -n -e $black'copying original iso  ...';
#sleep 1;
sudo rsync -avx --progress $loop $work &> /dev/null;
echo -e $green 'OK';
 
echo -n -e $black'unmount original iso  ...';
sleep 1;
sudo umount $loop;
echo -e $green 'OK';
 
echo -n -e $black'mounting squash file  ...';
sleep 1;
if [ -f $squash ]; then
        sudo mount -t squashfs -o loop  $squash $loop &> /dev/null;
	echo -e $green 'OK';
else
        echo -e $red 'cannot find filesystem.squashfs!';
        echo -e $black'bye!';
        exit;
fi
 
echo -n -e $black'checking new_squashdir...';
sleep 1;
if [ -d $new_squash_dir ]; then
       #sudo rm -rf $new_squash_dir;
	size=`sudo du -h -s  $new_squash_dir  | awk '{print $1}'`;
	echo -e $green 'OK. Warning: $new_squash_dir exists. Contents: ' $size;
else
        echo -e $red 'creating new squash dir';
        mkdir $new_squash_dir;
fi
 
echo -n -e $black'copying orig squashfs ...';
#sleep 1;
sudo rsync -av --progress $loop $new_squash_dir &> /dev/null;
size=`sudo du -h -s  $new_squash_dir  | awk '{print $1}'`;
echo -e $green 'OK. Copied over: ' $size ;
 
echo -n -e $black'unmount orig squashfs ...';
sleep 1;
sudo umount $loop;
echo -e $green 'OK';
 
echo -n -e $black'mounting dev > squash ...';
if [ -d $new_squash_dir ]; then
        sudo mount --bind /dev $new_squash_dir/dev &> /dev/null;
      	sudo mount --bind /var/run/dbus/ $new_squash_dir/var/run/dbus/ ;
	echo -e $green 'OK';
else
        echo -e $red 'cannot bind /dev!';
        echo -e $black'bye!';
        exit;
fi
 
echo -n -e $black'copying resolv.conf   ...';
if [ -f $new_squash_dir/etc/resolv.conf.orig ]; then
        sudo cp /etc/resolv.conf $new_squash_dir/etc/
else
	if [ -f $new_squash_dir/etc/resolv.conf ]; then
		sudo mv $new_squash_dir/etc/resolv.conf $new_squash_dir/etc/resolv.conf.orig
	fi
        sudo cp /etc/resolv.conf $new_squash_dir/etc/ 
 
fi
 
echo -e $green 'OK';
 
dns=`sudo cat $new_squash_dir/etc/resolv.conf | grep name | awk '{ print $2 }'`;
echo    -e $black'using this dns server ...' $green $dns;
 
echo    -e $black'chrooting: list chroot...'; $normal;
echo " ";
sudo chroot $new_squash_dir/ ls
 
echo " ";
echo -n -e $black'adding new repos      ...';
if [ -f $new_squash_dir/etc/apt/sources.list.orig ]; then
	sudo mv ./sources.list $new_squash_dir/etc/apt/
	echo -e $green 'OK';$normal;
else
	sudo cp $new_squash_dir/etc/apt/sources.list $new_squash_dir/etc/apt/sources.list.orig
	sudo mv ./sources.list $new_squash_dir/etc/apt/
	echo -e $green 'COPIED';$normal;
fi
 
echo " ";
echo    -e $black'chrooting: update     ...'; $normal;
sudo chroot $new_squash_dir/ apt-get update
 
echo " ";
echo    -e $black'chrooting: removing not needed language packages    ...'; $normal;
sudo chroot $new_squash_dir/   apt-get purge `dpkg -l language-pack-* | grep -v language-pack-el | grep -v language-pack-en | grep -v language-pack-gnome-en | grep -v language-pack-gnome-el | grep -v kde | grep -v Status | grep -v "Name" | grep -v "\Ό\ν\ο\μ\α" | awk '{print $2}'`
 
echo " ";
echo    -e $black'chrooting: installing essential/restricted packages ...';$normal;
answer=1;
while [  $answer -gt '0' ]; do
	choose_packages;
	answer=$?
	case $answer in
	1)
	sudo chroot $new_squash_dir/ apt-get install $build_packages;
	  ;;
	2)
	sudo chroot $new_squash_dir/ apt-get install $desktop_packages;
	  ;;
	3)
	sudo chroot $new_squash_dir/ apt-get install $devel_packages;
	  ;;
	4)
	sudo chroot $new_squash_dir/ apt-get install $multimedia_packages;
	  ;;
	5)
	sudo chroot $new_squash_dir/ apt-get install $math_packages;
	  ;;
        6)
        sudo chroot $new_squash_dir/ apt-get install $mce_packages;
          ;;
	7)
	sudo chroot $new_squash_dir/ apt-get install $kde_packages;
	;;
	8)
	sudo chroot $new_squash_dir/ apt-get install $kde_packages $desktop_packages $multimedia_packages $devel_packages;
	;;
        9)
        sudo chroot $new_squash_dir/ apt-get install $build_packages $desktop_packages $multimedia_packages $devel_packages $math_packages $mce_packages;
          ;;
	esac
done
 
#sudo chroot $new_squash_dir/ apt-get install $build_packages $desktop_packages $multimedia_packages $devel_packages $math_packages;
 
echo " ";
echo    -e $black'chrooting: adding greek language packages          ...';$normal;
sudo chroot $new_squash_dir/ apt-get install $greek_packages;
 
echo " ";
echo -n -e $black'cleaning squash dir   ...';$normal;
sudo chroot $new_squash_dir/ apt-get clean
echo -e $green 'OK';$normal;
 
echo " ";
echo -n -e $black'removing temp files   ...';$normal;
sudo chroot $new_squash_dir/ mv /etc/resolv.conf.orig /etc/resolv.conf
sudo chroot $new_squash_dir/ mv /etc/apt/sources.list.orig /etc/apt/sources.list
 
if [ -f $new_squash_dir/etc/apt/sources.list.orig ]; then
	echo -e $red 'FAIL!';$normal;
else
	echo -e $green 'OK';$normal;
fi
 
echo " ";
echo -n -e $black'updating squash file  ...';$normal;
sudo chroot $new_squash_dir dpkg-query -W --showformat='${Package} ${Version}\n' | grep -v deinstall > filesystem.manifest
sudo mv ./filesystem.manifest $work/casper/
echo -e $green 'OK';$normal;
 
echo " ";
echo -n -e $black'creating sed script   ...';$normal;
echo "/casper/d" > ./sedscript
echo "/libdebian-installer4/d" >> ./sedscript
echo "/os-prober/d" >> ./sedscript
echo "/ubiquity/d" >> ./sedscript
echo "/ubuntu-live/d" >> ./sedscript
echo "/user-setup/d" >> ./sedscript
echo -e $green 'OK';$normal;
 
echo -n -e $black'executing the script  ...';$normal
sudo sed -f ./sedscript < $work/casper/filesystem.manifest > filesystem.manifest-desktop
sudo mv filesystem.manifest-desktop $work/casper/
echo -e $green 'OK';$normal;
 
echo " ";
echo -n -e $black'making new squashfs   ...';$normal;
sudo mksquashfs $new_squash_dir/ $work/casper/filesystem.squashfs -noappend
echo -e $green 'OK';$normal;
 
echo " ";
echo -n -e $black'entering working dir  ...';$normal;
cd $work;
echo -e $green 'OK';$normal;
 
echo " ";
echo -n -e $black'updating md5sums file ...';$normal;
sudo find . -type f -print0 | xargs -0 md5sum > md5sum.txt
echo -e $green 'OK';$normal
 
echo " ";
echo -n -e $black'creating NEW ISO!!!   ...';$normal;
sudo mkisofs -r -v -V "UbuntuNew" -cache-inodes -J -l  -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -publisher "Dimitris Kalamaras" -p "[email protected]"  -o ../$newubuntu.iso .
 
cd ..
 
if [ -f $newubuntu.iso ]; then
        echo -e $green 'OK';$normal;
else
	echo -e $red 'Sorry. I failed to make the iso....';$normal;
fi
 
# make all sane!
tput sgr0
echo ' ' ;
echo -e $black'bye!';$normal;

Enjoy!

9 Responses to “melux: a custom ubuntu iso creation script!”

  1. hmm… I wish there was a Sidux port of that baby!

  2. It can be. “With a little help from my friends”….:)

  3. Interesting. I wonder how much more human and manageable the above would be if it were in Python. =)

  4. More human than bash? Bah… :P

  5. So, Im going to ask before I do this..
    This script will take an ISO, update it and then repackage it?

    And.. if this is the case does it remove the old kernels and obsolete files before repackaging?

  6. Yes, melux will do exactly that. It won’t update the kernel, but it will add several packages – these are predefined by me, but you can easily change them…For instance, open melux.sh with a text editor and search for desktop_packages or multimedia_packages. You can add whatever packages you want just after the equal sign.. Oh, use the version from the git repository.

  7. can I use it to make custom image of ubuntu server ?
    What I can do if I want to install one package form the source ?

  8. To my knowledge, ubuntu server is a stripped down ubuntu-desktop with added some server packages.

    I haven’t tested it, but I presume melux will work ok with ubuntu server iso.

    As for the source package, you just have to add source repositories to sources.list. So, yes, it can be done, but you need to modify melux.sh by adding the extra source repo line in lines 116-118.

  9. [...] προσφέρθηκα να φτιάξω ένα σκριπτάκι (μια εκδοχή του melux.sh) που κάνει remaster το εκάστοτε ISO του Ubuntu, δηλαδή του [...]

Leave a Reply