gcokeefe@postoffice.utas.edu.au
Vamos instalar uma distribuição de Linux como a Red Hat em uma partição, e usar ela para construir um novo sistema Linux em outra partição. Vou chamar o sistema que estaremos construindo de ``alvo'' e o sitema que estaremos usando para construi-lo de ``fonte'' (não confunda com código fonte que também estaremos usando.)
De forma que você vai precisar de uma máquina com duas partições separadas. Você pode usar uma instalação de Linux já existente como seu sistema fonte, mas não recomendaria isto. Se você errar um dos parâmetro de um dos comandos que vamos usar, você poderia acidentalmente instalar bobagens em seus sistema. Isso poderia levar à incompatibilidades e conflitos.
Hardware antigo de PC, a maior parte dos 486's e anteriores, tem uma
limitação irritante em suas bios. Eles não podem ler o disco rígido
depois dos primeiros 512M. Isso não é muito problemático para o Linux,
porque uma vez em funcionamento, ele faz seu próprio io (input/output
- entrada/saída), ignorando a bios. Porém para Linux que será
carregado por essas máquinas velhas, o kernel tem de residir em algum
lugar abaixo dos 512M. Se você tem uma dessas máquinas, vai precisar
separar uma partição completamente abaixo dos 512M, para montar como
/boot
em qualquer partição que estiver acima dos 512M.
A última vez que fiz isso, usei um Red Hat 6.1 como sistema fonte. Instalei o sistema base mais:
Eu também tinha o X-window e o Mozilla, assim eu podia ler a documentação fácilmente, mas isto não é realmente necessário. No momento em que terminei o trabalho, isto usou cerca de 350M de espaço em disco. (parece bastante, gostaria de saber porquê?)
O sistema alvo acabado tomou 650M, mas isto inclui todo o código fonte
e os arquivos intermediários da construção. Se o espaço for pouco,
você deve fazer um make clean
depois de cada pacote que for
construído. Ainda assim é quantidade que causa um pouco de
preocupação.
Finalmente, você precisa do código fonte para o sistema que estaremos construindo. Esses são os ``pacotes'' que eu discuti nesse documento. Eles podem ser obtidos num CD de código fontes, ou na Internet. Eu darei URL's para os sítios nos EUA e para os espelhos na Autrália.
agetty
e login
Para somá-los, você vai precisar:
Presumo que você pode instalar o sistema fonte sozinho, sem nenhuma ajuda minha. Daqui em diante presumo que isto já está feito.
A primeira marca nesse pequeno projeto é tornar o kernel inicializável
e mostrar uma mensagem ``panic'' porque ele não pode encontrar um
init
. Isso significa que teremos que instalar um kernel, e o
lilo. Contudo para instalar o lilo agradavelmente, precisaremos dos
arquivos de dispositivos no diretório /dev
do alvo. O lilo
precisa deles para fazer o acesso de baixo nível necessário para
escrever o setor de boot. MAKEDEV é o roteiro (script) que cria esses
arquivos de dispositivos. (Você pode apenas copiá-los do sistema fonte
é claro, mas isto é trapaça!) Mas antes de tudo, precisamos de um
sistema de arquivos para colocar tudo isso nele.
Nosso novo sistema estará em um sistema de arquivos. Portanto,
primeiro precisamos criar um sistema de arquivos usando
mke2fs
. Em seguida montá-lo em algum lugar. Sugiro
/mnt/target
. No que segue, assumo que este é ele onde
está. Você pode poupar um bocado do seu tempo colocando uma entrada em
/etc/fstab
de forma que quando ligar o sistema será montado
automaticamente.
Quando inicializarmos o sistema alvo, o que agora está em
/mnt/target
estará em /
.
Precisamos uma estrutura de diretórios no alvo. Dê uma olhada no FHS
(File Heirarchy Standard - Padrão de Hierarquia de Arquivos, veja
Links) para verificar o que isso deveria ser, ou
apenas vá para onde o alvo está montado (cd
) e cegamente
faça:
mkdir bin boot dev etc home lib mnt root sbin tmp usr var cd var; mkdir lock log run spool cd ../usr; mkdir bin include lib local sbin share src cd share/; mkdir man; cd man mkdir man1 man2 man3 ... man9
Visto que o FHS e a maior parte dos pacotes discordam sobre onde as páginas de manual deveriam ir, precisamos de um vinculo simbólico:
cd ../..; ln -s share/man man
Colocaremos o código fonte no diretório /usr/src
do alvo. Por
exemplo, se o sistema de arquivos do alvo está montado em
/mnt/target
e seus tarballs estão em /root
, você
faria:
cd /mnt/target/usr/src tar -xzvf /root/MAKEDEV-2.5.tar.gz
Não seja um completo idiota copiando o tarball para o lugar onde você o vai extrair ;->
Normalmente quando você instala software, você instala ele no sistema
que está rodando. Contudo nós não queremos fazer isto, queremos
instalar como se /mnt/target
fosse o sistema de arquivos
raiz. Diferentes pacotes tem diferentes meios de permitir isso. Para o
MAKEDEV você faz:
ROOT=/mnt/target make install
Você deve procurar por essas opções nos arquivos README e INSTALL ou
fazendo um ./configure --help
.
Dê uma olhada no Makefile
para ver o que ele faz com a
variável ROOT
que definimos neste comando. Em seguida dê uma
olhada na página de manual fazendo man ./MAKEDEV.man
para ver
como isto funciona. Você verá que o jeito de criar nossos arquivos de
dispositivos é cd /mnt/target/dev
e fazer ./MAKEDEV
generic
. Faça um ls
para ver todos os maravilhosos
arquivos de dispositivos ele fez para você.
Em seguida construiremos um kernel. Presumo que você já vez isso
antes, portanto vou ser breve. É mais fácil instalar o lilo se o
kernel que ele deverá inicializar já estiver ali. Volte ao diretório
usr/src
do alvo e descompacte o kernel linux ali. Entre na
árvore de diretórios do linux (cd linux
) e configure o kernel
usando seu método favorito, por exemplo make menuconfig
. Você
pode tornar a vida levemente mais fácil para você configurando um
kernel sem módulos. Se você configurar algum módulo, então terá de
editar o Makefile
, encontrar INSTALL_MOD_PATH
e
definir ele para /mnt/target
.
Agora você pode make dep
, make bzImage
, e se você
configurou módulos: make modules
, make
modules_install
. Copie o kernel arch/i386/boot/bzImage
e o mapa do sistema System.map
para o diretório
/mnt/target/boot
do alvo, e estamos prontos para instalar o
lilo.
O lilo vem com um ótimo roteiro chamado QuickInst
.
Descompacte o código fonte do lilo no diretório de fontes do alvo,
rode este roteiro com o comando ROOT=/mnt/target
./QuickInst
. Ele vai fazer perguntas à você sobre como quer que o
lilo seja instalado.
Lembre-se, já que definimos ROOT
para a partição alvo, iremos
informar os nomes relativos a esta. Portanto, quando ele perguntar
qual o kernel inicializar por padrão, responda /boot/bzImage
não /mnt/target/boot/bzImage
. Encontrei um pequeno
erro (bug) no roteiro, ele diz:
./QuickInst: /boot/bzImage: no such file
mas você pode simplismente ignorá-lo.
Onde devemons instruir ao QuickInst
colocar o setor de boot?
Quando reiniciarmos queremos ter a escolha de inicializar no sistema
fonte ou no sistema alvo, ou qualquer outro sistema que tivermos. E
queremos que o lilo que estamos construindo agora carregue o kernel de
nosso novo sistema. Como conseguiremos alcançar ambos os resultados?
Vamos divagar um pouco para ver como o lilo inicializa o DOS em um
sistema Linux de dupla inicialização (dual boot). O arquivo
lilo.conf
num sistema destes provavelmente é parecido com
esse:
prompt timeout = 50 default = linux image = /boot/bzImage label = linux root = /dev/hda1 read-only other = /dev/hda2 label = dos
Se a máquina for configurada deste modo, então o MBR (Master Boot
Record - Registro Mestre de Inicialização) é lido e carregado pela
bios, ela carrega o inicializador lilo que fornece uma linha de
comandos (prompt). Se você digitar dos
nele, o lilo carrega o
setor de boot de hda2, carregando o DOS.
O que faremos é exatamente a mesma coisa, exceto que o setor de boot
em hda2 terá um outro lilo nele - é ele que QuickInst
vai
instalar. Assim o lilo da distribuição Linux vai carregar o lilo que
construimos, e ele vai carregar o kernel que construimos. Você verá
dois lilos quando reiniciar.
Para encurtar a história, quando o QuickInst
perguntar onde
colocar o setor de boot, diga a ele o dispositivo onde seu sistema de
arquivos alvo está, por exemplo /dev/hda2
.
Agora modifique o lilo.conf
em seu sistema fonte, de forma
que tenha uma linha como esta:
other = /dev/hda2 label = target
rode o lilo e estaremos apto para inicializar o sistema alvo pela primeira vez.
Em seguida queremos instalar o init
, mas como praticamente
todos programas que rodam em Linux, o init
usa funções de
bibliotecas fornecidas pela biblioteca GNU C, glibc. Portanto teremos
que instalar esta primeiro.
Glibc é um pacote muito grande e complicado. Ela levou 90 horas para compilar em meu velho 386sx/16 com 8M de RAM. Mas levou apenas 33 minutos em meu Celeron 433 com 64M. Penso que a memória é a principal questão aqui. Se você tem apenas 8M de RAM (ou pior, menos!) prepare-se para uma longa compilação.
A documentação de instalação da glibc recomenda compilar em um diretório separado. Isso permite que você recomesse facilmente, apenas removendo este diretório. Você também pode querer fazer isto para poupar cerca de 265M do seu espaço em disco.
Descompacte o tarball glibc-2.1.3.tar.gz
(ou qualquer que
seja a versão) em /mnt/target/usr/src
como de costume. Agora,
precisamos descompactar os adicionais (add-ons) no diretório da
glibc. Então cd glib-2.1.3
, e descompacte os tarballs
glibc-crypt-2-1-3.tar.gz
e
glibc-linuxthreads-2.1.3.tar.gz
aqui.
Agora podemos criar o diretório para compilação, configurar, construir
e instalar a glibc. Estes são os comandos que usei, mas leia a
documentação você mesmo para ter certeza que você está fazendo o
melhor para sua circunstância. Contudo antes que você o faça, você
pode querer dar o comando df
para ver quanto espaço livre
você tem. Você pode dar o comando novamente depois que você construir
e instalar a glibc, para ver como ele consome espaço.
cd .. mkdir glibc-build ../glibc-2.1.3/configure --enable-add-ons --prefix=/usr make make install_root=/mnt/target install
Repare que temos outras formas de dizer ao pacote onde instalar.
Compilar e instalar binários do SysVinit é simples e direto. Há uma
pequena modificação a ser feita no Makefile
do subdiretório
src/
. Nas últimas quatro linhas, você precisa por
$(ROOT)
exatamente antes de /dev/initctl
, desta
maneira:
@ if [ ! -p /dev/initctl ]; then \
se torna:
@ if [ ! -p $(ROOT)/dev/initctl ]; then \
Esse arquivo de dispositivo initctl
é um meio de comunição
com o init. Por exemplo, a página de manual do init
diz que
este arquivo de dispositivo deveria ser usado no lugar de SIGPWR para
fazer o init desligar quando a energia estiver falhando, se estivermos
usando um no-break. A modificação que acabamos de fazer garante que
isso será feito no sistema alvo, não no fonte.
Logo que isto for feito, no subdiretório src
simplesmente
faça:
make ROOT=/mnt/target make install
Também existe um porção de roteiros associados com o
init
. Mas você terá que instalá-los manualmente. Eles são
definidos em uma hierarquia sob debian/etc
na árvore do
código fonte do SysVinit. Você pode simplesmente copiá-los direto para
o diretório etc
no sistema alvo, com alguma coisa como:
cd ../debian/etc; cp -r * /mnt/target/etc
. Obiviamente você
vai querer olhá-los antes de copiá-los!
Tudo está pronto para o kernel alvo carregar o init
quando
reiniciarmos. O problema agora é que os roteiros não irão rodar,
porque o bash
não está lá para interpretá-los. O
init
também tentará rodar os getty
, mas não há
getty
para ele rodar. Reinicie agora e certifique-se de que
não há mais nada errado.
A próxima coisa que precisamos é do Bash, mas o bash precisa do ncurses, portanto instalaremos ele primeiro. Ncurses substitui o termcap como forma de manipular telas de texto, mas ele também fornece compatibilidade regressiva suportando as chamadas do termcap. No interesse de ter um sistema limpo, simples e moderno, penso que é melhor desativar o velho método termcap. Você pode enfrentar problemas depois se compilar um aplicativo antigo que usa o termcap. Mas pelo menos você saberá o que está usando o que. Se precisar você pode recompilar o ncurses com suporte ao termcap.
Os comandos que usei são:
./configure --prefix=/usr --with-install-prefix=/mnt/target --with-shared --disable-termcap make make install
Fazer o Bash se instalar no lugar devido me custou bastante leitura, reflexão, tentativa e erro. As opções de configuração que usei são:
./configure --prefix=/mnt/target/usr/local --exec-prefix=/mnt/target --with-curses
Uma vez compilado e instalado o Bash, você precisa criar um vínculo
simbólico (symlink) como este: cd /mnt/target/bin; ln -s bash
sh
. Isso é porque os roteiros normalmente tem a primeira linha
como essa:
#!/bin/sh
Se você não fizer o vínculo simbólico, seus roteiros não serão capazes
de rodar, porque estarão procurando por /bin/sh
não
/bin/bash
.
Você poderia reiniciar novamente nesse ponto se quiser. Você deve
notar que agora os roteiros realmente rodam, embora você ainda não
pode efetuar login, porque não existem os programas getty
nem
login
.
O pacote util-linux contém agetty
e login
.
Precisamos de ambos para podermos efetuar login e obter o prompt do
bash. Depois de instalado, crie um vínculo simbólico de
agetty
para getty
no diretório /sbin
no
alvo. O getty
é um dos programas que presupostos a existir em
todos os sistemas Unix, por isso o vínculo é uma idéia melhor que
modificar o inittab
para rodar agetty
.
Ainda tenho um problema não resolvido com a compilação do
util-linux. O pacote também contém o programa more
, e não fui
capaz de persuadir o processo do make
vincular o
more
contra a biblioteca ncurses 5 no sistema alvo em vez da
ncurses 4 no sistema fonte. Vou dar uma olhada mais de perto nisso.
Você também vai precisar de um arquivo /etc/passwd
no sistema
alvo. Esse é onde o programa login
vai verificar para saber
se você está autorizado. Já que esse é apenas um sistema experimental
nesse estágio, você pode fazer coisas como definir apenas o usuário
root, e não solicitar senha!! Apenas coloque isso no
/etc/passwd
do alvo:
root::0:0:root:/root:/bin/bash
Os campos são separados por dois pontos, e da esquerda para direita eles são o id do usuário, senha (codificada), número do usuário, número do grupo, nome do usuário, diretório pessoal (home) e o shell padrão.
O último pacote que precisamos é o GNU sh-utils. O único programa que
precisamos dele nesse estágio é o stty
, que é usado no
/etc/init.d/rc
que é usado para mudar os níveis de execução
(runlevels), e para entrar no nível de execução inicial. Na verdade eu
tenho e uso um pacote que contém apenas o stty
, mas não me
lembro de onde ele veio. É melhor idéia usar o pacote GNU, porque
existem outras coisas nele que você vai precisar se aumentar o sistema
para fazê-lo usável.
Bom isto é tudo. Agora você deve ter um sistema que vai inicializar e
pedir um login. Digite ``root'' e você deverá ter um shell. Você não
será capaz de fazer muita coisa com ele. Não há nem mesmo um comando
ls
aqui para você ver seu trabalho manual. Pressione tab duas
vezes para ver os comandos disponíveis. Essa foi a coisa mais
satisfatória que eu consegui fazer.
Pode parecer que fizemos um sistema inútil aqui. Mas na verdade não
falta muito para que ele seja útil. Uma das primeiras coisas que você
teria que fazer é montar o sistema de arquivos raiz para leitura e
gravação. Há um roteiro do pacote SysVinit em
/etc/init.d/mountall.sh
que faz isso, e um mount -a
de forma que tudo é montado da forma que você especificar em
/etc/fstab
. Coloque um vínculo simbólico para ele com um nome
parecido com S05mountall
no diretório etc/rc2.d
do
alvo.
Você pode descobrir que esse roteiro usará comandos que você ainda não instalou. Nesse caso, encontre o pacote que contém os comandos e instale-o. Veja a seção Dicas Aleatórias para ajudar em como encontrar pacotes.
Dê uma olhada nos outros roteiros em /etc/init.d
. A maioria
deles será necessário em qualquer sistema sério. Vá colocando um por
um, certifique-se de que tudo está funcionando bem antes de colocar
mais.
Confira o FHS (veja a seção
Links). Ele tem
listas dos comandos que deveriam estar em /bin
e
/sbin
. Tenha certeza de ter todos esses comandos
instalados. Ou melhor ainda, encontre a documentação Posix que
especifica isso.
Daí em diante, é realmente apenas uma questão de lançar-se em mais e
mais pacotes até tudo que você quer estiver lá. Quanto antes você por
as ferramentas de construção como gcc
e make
melhor. Uma vez feito isto, você pode usar o próprio sistema alvo para
construir, o que é muito menos complicado.
Se você tiver um comando chamado coisa
num sistema Linux com
RPM, e quer uma ajuda para saber de onde obter os fontes, você pode
usar o comando:
rpm -qif `which coisa`
E se você tem o CD de fontes do Red Hat, você pode instalar o código fonte usando:
rpm -i /mnt/cdrom/SRPMS/o.que.ele.acabou.de.dizer-1.2.srpm
Isso vai colocar o tarball e qualquer patch da Red Hat em
/usr/src/redhat/SOURCES
.
/bin
, /sbin
e assim por
diante. Essa é uma boa referência se seu objetivo é fazer um sistema
mínimo mas completo.
Os direitos autorais deste documento pertencem à Greg O'Keefe - Copyright (c) 1999, 2000 Greg O'Keefe. Você pode usar, copiar, distribuir ou modificar isto, sem ônus, sob os termos da GNU General Public Licence. Por favor, me cite como autor se usar todo ou partes deste documento em outro documento.
A versão mais recente deste documento está em From Powerup To Bash Prompt
Gostaria de ouvir quaisquer comentários, críticas ou sugestões de melhoras que você tenha. Por favor, envie-as para Greg O'Keefe
Os nome de produtos são marcas registradas de seus respectivos proprietários, e por meio disto considerado adequadamente reconhecidos.
Existem algumas pessoas que quero agradecer, por ajudar que isto acontecesse.
Por me lembrar sobre o Unios
Por várias boas dicas sobre /etc/passwd
Quem me avisou que o syslogd precisa de /etc/services
, e me
apresentou a frase ``rolling your own'' para descrever a construção de
um sistema a partir do código fonte.
Por me chamar a atenção sobre Vico e seu ``verum ipsum factum'' (o conhecimento vem pela prática).
Por corrigir minha aritimética hexadecimal.
Por me mostrar alguns erros tipográficos.