Skip to main content

Ralsina.Me — Roberto Alsina's website

How to make your own distro in 3 not-so simple steps

This is a work in progress. There may be changes ev­ery now and then.

Right now, this is ver­sion 0.1 and many things are miss­ing.

I wrote in my blog that I missed not hav­ing a tool to eas­i­ly cre­ate my own dis­tro. Ok, there are some things around that will do it, but not the dis­tro I want­ed, which was to be a Cen­tOS de­riv­a­tive.

So, I delved deep in­to google and found just enough in­fo to make it work. This page was very use­ful (In fac­t, 80% of what I do is tak­en from there).

It's not pret­ty, but it's not dead­ly, ei­ther. What it is is bare­ly doc­u­ment­ed, so let's try to fix that.

In this ar­ti­cle, I will try to cre­ate my own Cen­tOS dis­tri­bu­tion (it will some­day try to be a Cen­tOS de­riv­a­tive with em­pha­sis on Xen called Xen­tos ;-).

We will not get there to­day, but we will cre­ate our own small­er dis­tro.

I will as­sume you are do­ing all this as root. Please don't tell me that what I tell you here ate your ma­chine, please?

Do it in a qe­mu vir­tu­al box! Have back­up­s! Do it as a reg­u­lar us­er in­stead!

Step 1: Setting up our playground

Get CD1 of Cen­tOS (or your favourite Ana­con­da+RPM based dsitro, I sup­pose).

Then, make a copy of it in­to a fold­er of your choice. Here, I will use /dis­tro/i386:

mkdir -p /distro/i386
cp -Rvf /media/cdrom/* /distro/i386

Now, you must make a de­ci­sion. Is it go­ing to be a dis­tro you will show some­one? Is it go­ing to be sub­stan­tial­ly dif­fer­ent from Cen­tOS or what­ev­er your orig­i­nal dis­tro is?

If yes, you will need to patch ana­con­da it­self so it us­es the right paths for your files and such, and change a bunch of the op­tions we pass to com­mands in this doc­u­men­t.

In the Cen­tOS ana­con­da rp­m, that's just touch­ing the patch Cen­tOS al­ready did to change that from "Red­Hat" to "Cen­tOS"... and chang­ing it, in my case, to "X­en­tOS", re­build­ing and us­ing the new, patched ana­con­da and ana­con­da-run­time RPM­s.

If you are just play­ing, or want to test things for a while, just use your dis­tro's name and be hap­py, be­cause it's sim­pler. In that case, just use Cen­tOS as the name.

Be­sides, it will tell me if you are pay­ing at­ten­tion ;-)

So, if you choose a name for your new dis­tro, re­name the Cen­tOS (or what­ev­er) fold­er:

mv /distro/i386/CentOS /distro/i386/XentOS

Now we can check the san­i­ty of our set­up (re­quires ana­con­da-run­time):

/usr/lib/anaconda-runtime/genhdlist --withnumbers --productpath=CentOS /distro/i386/

You should get no er­rors, and now you should have a new set of hdlist files:

[root@monty distro]# ls /distro/i386/CentOS/base/hdli* -l
-rw-r--r--  1 root root 2355640 abr  7 16:50 /distro/i386/CentOS/base/hdlist
-rw-r--r--  1 root root 4735400 abr  7 16:50 /distro/i386/CentOS/base/hdlist2

Step 2: Customizing your package selection

This is the fun part, and it is al­so trick­i­er.

Most­ly, you need to ed­it /dis­tro/i386/­Cen­tOS/base/­comp­s.xm­l. Which is a huge XML file. Here's how.

The file has a list of <group> tags at the be­gin­ning and lat­er, at the end, a <grouhier­ar­chy> tag.

A group is a group of pack­ages. That's what you use lat­er, in the in­staller, to de­cide what you can in­stal­l. The comp­s.xml we have now is that for the whole dis­tro. That's why it's so long.

I will show you how to re­duce it to the very ba­sic­s, so you can lat­er hack it to be what­ev­er you wan­t.

I re­moved all groups ex­cept for core and base (the first two). Be care­ful not to re­move the <grou­phier­ar­chy> piece.

Al­so re­moved this be­cause I re­moved the di­alup group:


Then, in the grou­phier­ar­chy sec­tion, I re­moved the fol­low­ing cat­e­gories: Desk­top­s, Ap­pli­ca­tion­s, Server­s, De­vel­op­men­t, Sys­tem... and you end with an emp­ty grou­phier­ar­chy ;-)

When­ev­er you ed­it comp­s.xm­l, you need to re­run gen­hdlist as above:

/usr/lib/anaconda-runtime/genhdlist --withnumbers --productpath=CentOS /distro/i386/

Now, you have a slim­mer in­stal­l, but the RPMS fold­er is full of un­nec­es­sary pack­ages. To fix that, you will need a tool that is no longer in re­cent dis­tros, called get­full­comp­ I got it back from an old box, you can get it here: get­full­comp­

Run it like this:

[root@monty distro]# /usr/share/comps-extras/ comps.xml /distro i386 > /dev/null
CRITICAL ERROR: Unable to find package mcelog
CRITICAL ERROR: Unable to find package openCryptoki
CRITICAL ERROR: Unable to find package prctl
CRITICAL ERROR: Unable to find package elilo
CRITICAL ERROR: Unable to find package iprutils
CRITICAL ERROR: Unable to find package ppc64-utils
CRITICAL ERROR: Unable to find package s390utils
CRITICAL ERROR: Unable to find package yaboot

Hon­est­ly, I don't know what's that. Those pack­ages are not even use­ful (some don't even come with Cen­tOS), so I sim­ply re­moved the ref­er­ences to them from comp­s.xm­l.

Now this gets bor­ing for a while...

Move all your RPMs else­where, Then, re­run gen­hdlist, re­run get­full­comp­

[root@monty distro]# mv /distro/i386/CentOS/RPMS/*.rpm /distro/rpms/
[root@monty distro]# /usr/lib/anaconda-runtime/genhdlist --withnumbers --productpath=CentOS /distro/i386/
[root@monty distro]# /usr/share/comps-extras/ comps.xml /distro i386 > /dev/null
CRITICAL ERROR: Unable to find package NetworkManager
CRITICAL ERROR: Unable to find package OpenIPMI
CRITICAL ERROR: Unable to find package acl
CRITICAL ERROR: Unable to find package acpid

Ob­vi­ous­ly, it's com­plain­ing be­cause you took away all the pack­ages... but it will on­ly com­plain about those you re­al­ly need! So, put those back in (this is a lit­tle too much work... try to fig­ure out a script to do it) un­til run­ning geth­dlist and get­full­comps gives no "Un­able to find" er­rors:

[root@monty rpms]# mv specspo-9.0.92-1.3.noarch.rpm slocate-2.7-13.el4.6.i386.rpm /distro/i386/CentOS/RPMS/
[root@monty rpms]# /usr/lib/anaconda-runtime/genhdlist --withnumbers --productpath=CentOS /distro/i386/
[root@monty rpms]# /usr/share/comps-extras/ comps.xml /distro i386 > /dev/null

CRITICAL ERROR: Unable to resolve dependency chkconfig for NetworkManager
CRITICAL ERROR: Unable to resolve dependency dbus for NetworkManager
CRITICAL ERROR: Unable to resolve dependency dbus-glib for NetworkManager

As you can see, get­full­comps checks de­pen­den­cies, so that you are not miss­ing any pack­ages you re­quire!

So, we fix those by putting back some more pack­ages!

[root@monty rpms]# mv usermode-1.74-1.i386.rpm ../i386/CentOS/RPMS/
[root@monty rpms]# /usr/lib/anaconda-runtime/genhdlist --withnumbers --productpath=CentOS /distro/i386/
[root@monty rpms]# /usr/share/comps-extras/ comps.xml /distro i386 > /dev/null

Re­mov­ing pack­ages from a dis­tro is a pain in the but­t. Adding them is eas­ier: you add the ones you wan­t, then you get com­plaints about the miss­ing ones. I want a tool that gives me a list of all the pack­ages noone re­quires, in­stead!

But hey, do­ing this we are re­mov­ing over 200 pack­ages.

Al­so, there are a few pack­ages that are re­quired for the in­stall­er to work... but it does­n't tell you!

Add these to your RPMS di­rec­to­ry if you don't have them (although some are on­ly for the graph­i­cal in­staller):


Re­run gen­hdlist and get­full­comp­ (y­ou may need to add some de­pen­den­cies again).

In re­al life, you would al­so re­move or add some groups or pack­ages in your comp­s.xm­l. Well, I leave that as an ex­er­cise for now...

Step 3: Creating the CD

We will cre­ate a sin­gle CD be­cause this dis­tro is smal­l. If you add more pack­ages you may end with more than one, of course.

Cre­ate the /dis­tro/p­kgorder file:

export PYTHONPATH=/usr/lib/anaconda
/usr/lib/anaconda-runtime/pkgorder /distro/i386 i386 CentOS| tee /distro/pkgorder.txt

Build the in­stall­er im­ages:

/usr/lib/anaconda-runtime/buildinstall --comp xentos --pkgorder /distro/pkgorder.txt \
--product "CentOS Linux" --release "CentOS Linux" --version 0 --prodpath CentOS /distro/i386/

If you get an er­ror like this:

rpm2cpio: /distro/i386/CentOS/RPMS/anaconda-runtime-[0-9]*: No such file or directory

you need to add the ana­con­da-run­time pack­age in the RPMS fold­er. I am not sure why this is nec­es­sary, but when I did­n't, I got er­rors lat­er. You can find the right pack­age in your dis­tro's CD­s, some­where, then do gen­hdlist and get­full­comp­ as be­fore. Fix any de­pen­den­cies is­sues that arise now, again, just like be­fore.

Al­so, in a lat­er stage, you will want to use your cus­tom ana­con­da-im­ages RP­M, for ex­am­ple, so your dis­tro has its own ban­ner ;-)

So, you run buildin­stal­l, and you should get stuff like this (it will take a while):

Running buildinstall...
/distro/i386/buildinstall.tree.4526 /distro
Going to run buildinstall again
Building images...
Assembling package list...
Expanding text packages...
Expanding graphical packages...
Running mkcramfs  /tmp/treedir.4542/instimage /tmp/instimage.img.12029
Wrote /distro/i386/CentOS/base/stage2.img (42940k)
Writing .discinfo file
timestamp not specified; using the current time

It should not com­plain about be­ing un­able to link di­rec­to­ries, or any­thing of the kind!

Now, you run split­tree. This is on­ly nec­es­sary if you have more than one CD, but hey, let's pre­tend, so you know it for lat­er!

mkdir /distro/source
/usr/lib/anaconda-runtime/ --arch=i386 --total-discs=1 --bin-discs=1 \
--src-discs=1 --release-string="CentOS Linux" --pkgorderfile=/distro/pkgorder.txt \
--distdir=/distro/i386 --srcdir=/distro/source --productpath=CentOS
First package on disc1: hwdata-0.146.18.EL-1.noarch.rpm
Last package on disc1 : net-snmp-5.1.2-11.EL4.6.i386.rpm
i386-disc1 size: 336M
i386-disc1 size: 336M

And now we should have a /dis­tro/i386-dis­c1, which is the ba­sis for our ISO im­age.

First we need to fix the hdlist files again, but this time in i386-dis­c1:

rm -f /distro/i386-disc1/fedora/base/hdlist*
/usr/lib/anaconda-runtime/genhdlist --withnumbers --fileorder /distro/pkgorder.txt \
/distro/i386-disc[123] --productpath CentOS

So... let's do it:

mkisofs -b isolinux/isolinux.bin -c isolinux/ -no-emul-boot \
-boot-load-size 4 -boot-info-table -v -r -T -J -V CentOS-0.0.1-D1 -o \
/distro/CentOS-0.0.1-D1.iso /distro/i386-disc1

If you had more than one dis­c, you would cre­ate the ISO im­ages like this ex­am­ple for disc 2 (but I have not test­ed it):

mkisofs -JR -l -V CentOS-0.0.1-D2  -o /distro/CentOS-0.0.1-D1.iso /distro/i386-disc2

As you can see, our iso is small­er...

[root@monty distro]# ls -lh *iso
-rw-rw-r--  1 ralsina ralsina 634M mar 15 06:49 CentOS-4.3-i386-bin1of4.iso
-rw-r--r--  1 root    root    423M abr  7 18:14 CentOS-0.0.1-D1.iso

You can test it on a vir­tu­al ma­chine now, for ex­am­ple us­ing VMWare or QE­mu.

Where to go from here?

Some is­sues re­main:

  • What is com­p­s.xm­l's twin yum­­group­s.xml for?

  • i386/re­po­­data/ has the wrong da­­ta in it

  • the graph­i­­cal in­­stal­l­er does­n't work much

  • You can on­­ly in­­stall "Cus­­tom"

  • The Pack­­age group se­lec­­tion of­fers on­­ly "Ev­ery­thing"

  • The In­­stal­l­er says Cen­­tOS ev­ery­where...

  • Many, many oth­­er­s.

Maybe some­day they will be fixed!

Now you have ev­ery­thing in place to up­date RPM­s, or re­place them with your own thing... want to boot us­ing runit in­stead of SysV init? Want to make it lean­er? Want to make a desk­top 1-CD dis­tro?

Well, get on the job, man! :-)

In the fu­ture, I should try hack­ing ana­con­da it­self, and see what I can find.

Francenildo Pereira Alves / 2006-07-24 01:22:

Basically I've been back at it, trying to do a buildinstall, and with every progress I make I continue to get the same error when the CD boots - no cd was found that matches your boot media.......

I've hacked into the source for anaconda and filled it up with some debug outputs while getting to know my way around a little bit, and I've found out where its going wrong. The buildstamps do not match.

I have one buildstamp (/.buildstamp) that is stamped 200605251433.0935 and another one (/mnt/runtime/.buildstamp) that is stamped 200603142328.0935. That causes verifyStamp (found in loader2/method.c) to fail, causeing the message.

Now I know the cause, how do I find the solution? I see that calls mk-stamp, which puts the current date/time/arch into /tmp/makebootdisk.dir.$$/.buildstamp, which appears to be compiled into the initrd.img on the cdrom (/isolinux/initrd.img). So the question is where is it getting the 200603 build stamp (original CentOS build is my guess). And why doesn't the buildinstall process use the same buildstamps for each place. I could hack mk-images to hard code the 200603 stamp, but I would prefer it to stamp it to the correct build date/time.

Any information would be fantastic.

Gabriel Gunderson / 2006-09-20 17:32:

Nice post. I'd be interested in knowing how your Xen hacking is going. How does RHEL 5 (and CentOS 5) including Xen figure into the picture?

Roberto Alsina / 2006-09-20 19:19:

Well, if they do it, there is no point on me spending my time in it :-)

Tikendrajit / 2008-12-11 09:44:

Hi Roberto
This is really a nice post from you.
Lately I have been trying to build a custom Distro so that I can distribute to the students. ( This post happens to be a great help to me though I haven't tried it so far.

Can you please update the latest version of your post.

Also send me you email id so that I can get in touch with you for my distro.


NABH / 2011-05-31 10:19:

I really appreciate your post and you explain each and every point very well.Thanks for sharing this 
information.And I’ll love to read your next post too.

employment background check / 2011-12-27 23:22:

Hi very nice article