# FreeBSD From Scratch

Jens
Schweikhardt

    schweikh@FreeBSD.org

2002
Jens Schweikhardt
$FreeBSD$

&scratch.ap; explica la instalación totalmente automatizada de un sistema &os; hecho a medida y compilado desde las fuentes, proceso que incluye además la compilación de sus ports favoritos y configurado para coincidir con su idea del sistema perfecto. Si cree que `make world` es un concepto fascinante &scratch.ap; lo amplía hasta ser `make evenmore`. N. del T. : Juego de palabras intraducible basado en el nombre que en &os; se da al proceso de recompilar todo el sistema desde los fuentes, `make world`, que podría traducirse muy libremente como hacer, o más bien rehacer el mundo entero y `make evenmore`, osea, hacer más aún.

&trans.es.carvay;

## Introducción

¿Ha actualizado alguna vez su sistema mediante `make world`?. Si solamente tiene un sistema en sus discos se encontrará con un problema. Si installworld falla a la mitad su sistema quedará dañado e incluso puede ser incapaz de arrancar de nuevo. O quizás installworld se ha ejecutado sin problemas pero el nuevo kernel no arranca. Se impone buscar el CD de Rescate y tratar de encontrar algo útil en aquellos backups que hizo hace seis meses.

Creo en el paradigma de al actualizar sistemas operativos instala desde cero. Haciéndolo así, esto es, al borrar sobreescribiendo en los discos o mejor dicho las particiones, nos aseguraremos de no dejar datos antiguos en ellos, un aspecto éste del que la mayoría de los procesos de actualización no se preocupan en absoluto. Por otra parte borrar las particiones significa que tendrá que recompilar/reinstalar todos sus ports y packages y después de eso rehacer todas y cada una de las configuraciones que con muchos esfuerzos atesoraba. Si usted también piensa que ésta tarea debería automatizarse siga leyendo.

## ¿Por qué (no) debería interesarme &scratch.ap;?

Esa es una pregunta muy razonable. Tenemos sysinstall, una compilación del kernel que funciona sin sorpresas y tenemos también las herramientas de entorno de usuario.

El problema que tiene sysinstall es que está extremadamente limitado cuando se trata de qué, dónde y cómo queremos que haga la instalación.

- Normalmente se usa para instalar distribuciones precompiladas y packages desde diversas fuentes (CD, DVD, FTP). No puede instalar el resultado de `make buildworld`.

- No puede instalar un segundo sistema en un directorio de un sistema en funcionamiento.

- No puede hacer una instalación en particiones Vinum.

- No puede compilar ports, sólo instala packages precompilados.

- Es difícil automatizar mediante scripts o incluso hacer de forma manual los cambios que considere necesarios después de la instalación

- Por si todo esto fuera poco sysinstall está semioficialmente al final de su Ciclo de Vida Útil.

El archiconocido proceso de construír/instalar el mundo (build/install world), explicado en el Handbook, por defecto realiza la tarea de sustituír el sistema existente. Sólo respeta el kernel y los módulos. Los binarios del sistema, los ficheros de cabecera y muchos otros ficheros son sobreescritos; hay ficheros obsoletos que se quedan donde estaban y pueden causar sorpresas. Si el proceso de actualización falla por alguna razón puede ser difícil o incluso imposible volver a dejar el sistema en el estado inicial.

&scratch.ap; resuelve todos esos problemas. La estrategia es simple: utiliza un sistema en funcionamiento para instalar un nuevo sistema en un árbol de directorios y montar nuevas particiones limpiamente en ese árbol. Muchos ficheros de configuración pueden copiarse al sitio que les corresponda y &man.mergemaster.8; se encargará de aquellos a los que no. Pueden hacerse cambios discrecionales tras la instalación del nuevo sistema desde el viejo, como si el nuevo sistema estuviera dentro de un chroot. El proceso tiene tres fases, cada una de los cuales consiste en ejecutar un script de shell o invocar `make`:

1. `fase_1.sh`: Crea un sistema nuevo y capaz de arrancar en un directorio vacío y combina o copia tantos ficheros como sea necesario. Una vez acabado esto arranca el nuevo sistema.

2. `fase_2.sh`: Instala los ports que hayamos elegido.

3. `fase_3.mk`: Remata la configuración del software instalado en la fase anterior.

Una vez que ha usado &scratch.ap; para construír un segundo sistema y ha comprobado que funciona satisfactoriamente durante unas cuantas semanas puede usarlo de nuevo para reinstalar el sistema original. Desde ese momento cada vez que crea que debe actualizar un sistema simplemente elija las particiones que hay que borrar y reinstalar.

Puede que haya oído hablar o incluso haya usado ya Linux From Scratch, LFS para ser más breve. LFS abarca también cómo construír e instalar un sistema desde cero en particiones vacías partiendo de un sistema en funcionamiento. El objetivo de LFS parece ser mostrar la razón de ser y de estar de todas y cada una de las partes del sistema (como el kernel, el compilador, los dispositivos, la shell, la base de datos de terminales, etc.) y los detalles de la instalación de cada parte. &scratch.ap; no entra en detalles tan exahustivos. Mi intención es facilitar una instalación automatizada y completa, no explicar cada detalle escabroso del ciclópeo proceso que arrancamos cuando hacemos un `make world`. Si desea usted explorar &os; de modo tan profundo comience por leer `/usr/src/Makefile` y siga cuidadosamente lo que sucede al teclear `make buildworld`.

Hay también algunos detalles delicados con los que me encontré durante el desarrollo de &scratch.ap; que debería tener muy en cuenta.

- El sistema no puede ser usado normalmente durante la compilación de los ports que tiene lugar en la segunda fase. Si va a ejecutar el proceso en un servidor en producción tenga en cuenta el tiempo de parada provocado por la fase dos. Los ports compilados por `fase_2.sh` necesitan aproximadamente 4 horas para acabar en un sistema SCSI AMD1800+ con discos de 10.000 rpm y 1GB de RAM.

## Requisitos previos

Para poder usar &scratch.ap; necesitará lo siguiente:

- Un sistema &os; con el árbol de ports y los fuentes instalados.

- Al menos una partición vacía donde instalaremos el nuevo sistema.

- Experiencia en el uso de &man.mergemaster.8; o al menos no tener miedo de usarlo.

- Si su acceso a Internet es lento o si no dispone del mismo necesitará los distfiles de los ports que vaya a instalar.

- Conocimientos básicos de confección de scripts de shell con la shell Bourne, &man.sh.1;

- Finalmente, debería ser capaz de decirle a su boot loader (cargador de arranque) cómo arrancar el nuevo sistema, en modo interactivo o mediante un fichero de configuración.

## Primera Fase: Instalación del Sistema

Lo que vamos a explicar más adelante es mi `fase_1.sh`. Tendrá que modificarlo en varios sitios para que cuadre con su propia idea del sistema perfecto. He intentado incluír todos los comentarios posibles en los sitios donde debería usted introducir sus cambios. Los puntos a estudiar son:

- Esquema de particiones.

  No estoy de acuerdo con la idea de una sola partición inmensa en la que instalar todo el sistema. Mis sistemas tienen generalmente al menos una partición para `/`, `/usr` y `/var` con `/tmp` enlazado simbólicamente a `/var/tmp`. Además comparto los sistemas de ficheros en los que ubico `/home` (los directorios de los usuarios), `/home/ncvs` (réplica del repositorio de &os;, `/usr/ports` (el árbol de ports), `/src` (diversos árboles de fuentes de procedencias varias) y `/share` (otros datos compartidos que no necesitan ser guardados, por ejemplo mensajes de news.

- Lujos.

  Me refiero a lo que usaremos inmediatamente tras el arranque del nuevo sistema e incluso antes de la segunda fase. En mi caso se trata de `shells/zsh` puesto que es la shell que aparece en mi cuenta de usuario en `/etc/passwd`. De todos modos la tarea puede culminarse sin esos lujos (de ahí su nombre), todo lo que necesita es entrar en el sistema como root y pasar a la siguiente fase.

  ¿Por qué no instalar entonces todos mis ports en la primera fase?: en teoría y en la práctica nos encontraremos con problemas de arranque y de consistencia: durante la primera fase tendrá funcionando su viejo kernel mientras el entorno chroot dispone de sus propios binarios y ficheros de cabecera todos nuevos. Si por ejemplo el sistema nuevo integra una nueva llamada al sistema (conforme a sus cabeceras) algunos scripts de configuración podrían intentar usarla y en concuencia ver muertos sus procesos al tratar de ejecutarse en el viejo kernel. He tenido problemas de otro tipo al intentar construír `lang/perl5`.

Antes de ejecutar `fase_1.sh` asegúrese de haber cumplido con las tareas previas a un `make installworld installkernel`, es decir:

- haber adaptado el fichero de configuración de su kernel

- haber completado sin errores `make buildworld`

- haber completado sin errores`KERNCONF= nombre_de_su_kernel`

Cuando ejecute `fase_1.sh` por primera vez y copie sus ficheros de configuración de su sistema en funcionamiento a su nuevo sistema no están al día con respecto a lo que hay bajo `/usr/src`, así que `mergemaster` le preguntará por lo que quiere hacer. Le recomiendo combinar los cambios. (Nota del traductor: merge (to): unir, fusionar, mezclar). Si se cansa de pelear con los diálogos de `mergemaster` puede simplemente actualizar sus ficheros una vez en el sistema original (pero sólo si existe esa opció: por ejemplo, si uno de sus sistemas usa `-STABLE` y el otro `-CURRENT` los cambios tienen bastantes probabilidades de ser incompatibles). En posteriores usos de `mergemaster` detectará que los ID de las versiones RCS de esos ficheros coinciden con los que están bajo `/usr/src` y no les prestará más atención.

El script `fase_1.sh` detendrá su ejecución si falla alguno de los comandos que contiene (si alguno da una salida distinta de cero) por incluír `set -e`, así que es imposible que pase por alto algún error. Antes de seguir adelante debería asegurarse de que no hay errores en su versión de `fase_1.sh`.

En `fase_1.sh` invocamos `mergemaster`. Tanto si alguno de los ficheros requiere ser combinado como si no, `mergemaster` emitirá el siguiente mensaje

    *** Comparison complete

    Do you wish to delete what is left of /var/tmp/temproot.fase1? [no] no

es decir

    *** Comparación completada

    ¿Quiere borrar el contenido de /var/tmp/temproot.fase1? [no] no

Por favor, responda `no` o simplemente pulse Enter. Eso es debido a que `mergemaster` habrá dejado unos cuantos ficheros de longitud igual a cero en `/var/tmp/temproot.fase1` y los copiará al nuevo sistema (a menos que ya estén ahí).

Después mostrará los ficheros que ha instalado mediante &man.more.1; o si lo prefiere mediante &man.less.1;):

    *** You chose the automatic install option for files that did not
        exist on your system.  The following were installed for you:
          /rootnuevo/etc/defaults/rc.conf
          ...
          /rootnuevo/COPYRIGHT

    (END)

es decir

    *** Ha elegido la opción de instalar automáticamente
         los ficheros que no existen en su sistema. Han sido instalados los
         siguientes:
           /rootnuevo/etc/defaults/rc.conf
           ...
           /rootnuevo/COPYRIGHT

Teclée q para salir del paginador. Ahora se le informará sobre `login.conf`:

    *** You installed a login.conf file, so make sure that you run
        '/usr/bin/cap_mkdb /newroot/etc/login.conf'
        to rebuild your login.conf database

        Would you like to run it now? y or n [n]

es decir

    *** Ha instalado un fichero login.conf así que
        asegúrese de ejecutar '/usr/bin/cap_mkdb /rootnuevo/etc/login.conf'
        para reconstruír la base de datos de login.conf

       ¿Quiere ejecutarlo ahora mismo? (s)i o (n)o [n]

La respuesta no tiene importancia puesto que ejecutaremos &man.cap.mkdb.1; en todos los casos.

Todo lo que hace `fase_1.sh` queda registrado en un fichero log para que pueda examinarse con detalle si es preciso.

Éste es el `fase_1.sh` del autor, así que tendrá que modificarlo a conciencia, en especial los pasos 1, 2, 5 y 6.

Por favor, ponga una atención esmerada a las entradas en las que aparece &man.newfs.8;. Si bien es cierto que es imposible crear nuevos sistemas de archivos en particiones montadas nuestro script no tendrá ningún inconveniente en borrar cualquier partición que no esté montada y con los nombres que aparezcan en él, en nuestro caso `/dev/da3s1a`, `/dev/vinum/var_a` y `/dev/vinum/usr_a`. Puede provocar un desastre, así que asegúrese de cambiar los nombres de los dispositivos como corresponda.

Descargue `fase_1.sh`.

La ejecución de éste script instala un sistema equipado con lo siguiente:

- Usuarios y grupos heredados del anterior sistema.

- Acceso a Internet mediante Ethernet y PPP protegido por un cortafuegos.

- NTP y zona horaria correctas.

- Algunos ficheros secundarios como `/etc/ttys` e `inetd`.

Hay otras áreas listas para ser configuradas pero no las tocaremos hasta concluír la segunda fase. Por ejemplo, hemos copiado unos cuantos ficheros para configurar la impresión y X11. Sin embargo la impresión suele necesitar de aplicaciones que no se encuentran en el sistema base, por ejemplo PostScript. X11 no funcionará hasta que no compilemos el servidor, las bibliotecas y los programas.

## Segunda Fase: Instalación de ports

En ésta fase es posible instalar packages (que vienen precompilados) en lugar de compilar ports. Para poder hacerlo convertiremos `fase_2.sh` en poco más que una lista de comandos `pkg_add`. Confío en que será usted capaz de escribir un script como ese. Ahora nos concentraremos en el sistema tradicional y mucho más flexible de funcionamiento de los ports.

El siguiente script `fase_2.sh` es el que yo uso para instalar mis ports favoritos. Puede ejecutarse tantas veces como sea preciso y no prestará atención a los ports que ya estén instalados. Incluye también soporte para la opción `-n` que hace un ensayo general con todo, es decir, muestra lo que hubiera sucedido si se hubiera ejecutado. Seguro que tiene que editar la lista de ports y probablemente tenga que cambiar unas cuantas variables de entorno.

La lista de ports consiste en líneas de dos o más palabras separadas por espacios: la categoría y el port. Es opcional situar detrás un comando de instalación que compilará e instalará el port (por defecto `make install`). Se ignoran las líneas vacís y las que comienzan por #. La mayoría de las veces es suficiente incluír el nombre del port y la categoría a que pertenece pero existen unos pocos ports en cuya compilación podemos afinar mucho asignando valores a variables de `make`; veamos un ejemplo:

    www mozilla make WITHOUT_MAILNEWS=yes WITHOUT_CHATZILLA=yes install
    mail procmail make BATCH=yes install

De hecho puede usted usar comandos de shell a su criterio, así que no tiene que limitarse a simples invocaciones de `make`:

    java linux-sun-jdk13 yes | make install
    news inn-stable CONFIGURE_ARGS="--enable-uucp-rnews --enable-setgid-inews" make install

Observe que la línea de `news/inn-stable` es un ejemplo de una asignación de entrada a la variable del intérprete de mandatos `CONFIGURE_ARGS`. El fichero `Makefile` del port la usará como valor inicial y la completará con otros argumentos esenciales. La diferencia respecto a a especificar la variable para `make` en la línea de comandos mediante

    news inn-stable make CONFIGURE_ARGS="--enable-uucp-rnews --enable-setgid-inews" install

está en que esto último sustituye directamente el valor en lugar de completarlo. El método más adecuado depende de cada port en particular.

Compruebe cuidadosamente que ninguno de sus ports tenga una instalación interactiva, es decir, que ninguno deberí intentar recibir de stdin nada que no le dé usted en stdin. Si alguno lo hace leerá la siguiente o siguientes líneas de éste documento y no entenderá nada de nada. Si `fase_2.sh` pasa por alto un port o cesa su ejecución sin razón aparente es muy posible que esa sea la razón.

He aquí `fase_2.sh`. Crea un fichero log por cada port que instala y les da nombres según el esquema `DIRECTORIO_LOG/categoría+port`. Si no tiene una copia de su `fase_2.sh` en una partición compartida no olvide copiarlo al sistema nuevo antes de arrancarlo.

Descargue `fase_2.sh`.

## Tercera Fase

Ya hemos concluído la segunda fase y ya están instalados sus queridísimos ports, pero algunos de ellos requieren un poco de configuración. En eso consistirá la tercera fase, añadir los detalles específicos de las configuraciones. Podría haberlos integrado en el script `fase_2.sh` pero creo que hay una diferencia conceptual entre instalar un port y en modificar la configuración con la que viene por defecto para adaptarla a nuestros gustos o necesidades y creo por lo tanto que esa diferencia justifica una separación en una fase propia.

He creído más conveniente implementar la tercera fase como un `Makefile` porque admiten la selección de lo que quiera configurar tecleando simplemente:

    &prompt.root; make -f fase_3.mk
              nombre_del_port

Al igual que con `fase_2.sh` asegúrese de que dispone de una copia de su `fase_3.mk` una vez que arranca el sistema nuevo, bien situándolo en una partición compartida bien copiándolo en algún lugar dentro del nuevo sistema.

Descargue `fase_3.mk`.

## Restricciones

La instalación automatizada de un port puede resultar difícil si es interactiva y no soporta `make BATCH=YES install`. En algunos casos la interacción se reduce a teclear `yes` cuando se le pregunta si acepta alguna licencia. Si esa entrada de datos ha de llegar por la entrada estándar simplemente redirigiremos las respuestas pertinentes a la orden de instalación (que suele ser `make install`; ese es el modo en el que hemos procedido con `java/linux-sun-jdk13` en `fase_2.sh`).

No obstante ésta estrategia no funciona con `editors/staroffice52`, que exige que X11 esté funcionando. El proceso de instalación comprende un buen número de pulsaciones de ratón y de tecleo, con lo que es imposible automatizarlo tal y como se hace con otros ports. Sin embargo el siguiente atajo workaround nos soluciona el problema: previamente he creado un `staroffice` en el sistema original con

    &prompt.root; cd /usr/ports/editors/staroffice52
    &prompt.root; make package
    ===>  Building package for staroffice-5.2_1
    Creating package /usr/ports/editors/staroffice52/staroffice-5.2_1.tbz
    Registering depends:.
    Creating bzip'd tar ball in '/usr/ports/editors/staroffice52/staroffice-5.2_1.tbz'

y durante la segunda fase usamos:

    &prompt.root; pkg_add /usr/ports/editors/staroffice52/staroffice-5.2_1.tbz

Debe usted también tener muy en cuenta posibles problemas con los ficheros de configuración a la hora de actualizar. En general no sabemos cuándo van a hacerse cambios en el formato o el contenido de un fichero de configuración. Es posible que haya que añadir un nuevo grupo a `/etc/group`, o quizás `/etc/passwd` necesite un nuevo campo en sus entradas. Éstas cosas han sucedido en alguna ocasión anteriormente. Si simplemente copiamos un fichero de configuración del sistema viejo al nuevo será suficiente la mayoría de la veces pero ya hemos visto dos casos en los que no lo era. Si actualiza su sistema siguiendo el sistema ortodoxo (sobreescribiendo los ficheros antíguos) tendrá que usar `mergemaster` para proceder con los cambios que quiera incluír en la configuración de su nuevo sistema, teniendo en cuenta que entre esos cambios hay o puede haber nuevos ficheros. Por desgracia `mergemaster` sólo es útil con ficheros del sistema base y no para aquellos relacionados con los ports. Además, ciertas aplicaciones parecen especialmente diseñadas para sacarme de mis casillas por el procedimiento de cambiar el fichero de configuración cada quince días. Lo único que puede hacerse es estar alerta, sobre todo cuando cambia el número de versión. En ocasiones anteriores he tenido que modificar o reescribir ficheros para servidores web, servidores y clientes de news. Cualquier tipo de software cuyo mantenimiento sea muy activo es un firme candidato a que sus ficheros de configuración merezcan nuestro examen.

He usado &scratch.ap; varias veces para actualizar un sistema `5-CURRENT` a `5-CURRENT`, esto es, nunca he intentado instalar `5-CURRENT` desde un sistema `4-STABLE` o viceversa, pero dada la cantidad de cambios existentes entre las diferentes RELEASE no sería insensato esperar que esa tarea sea un tanto compleja. Usar &scratch.ap; para actualizaciones dentro del campo de `4-STABLE` debería ser mucho menos penoso (aunque yo aún no lo he intentado). Si quiere hacerlo debería tener en cuenta lo siguiente:

- Si no usa el sistema de ficheros de dispositivo (`devfs`) puede necesitar crear los dispositivos necesarios para su hardware con &man.MAKEDEV.8; en la primera fase, sexto paso.