| Más Allá de Linux From Scratch: Versión 5.0 | ||
|---|---|---|
| Anterior | Capítulo 3. Configuración posterior al LFS | Siguiente |
Los programas para leer páginas de manual e info pueden procesar transparentemente páginas comprimidas con gzip o bzip2. Sin embargo, las cosas no son tan simples: los directorios man tienden a contener enlaces (duros o simbólicos) que arruinan ideas simples como la de ejecutar recursivamente gzip sobre ellos. Un método mejor es usar el siguiente guión.
cat > /usr/bin/compressdoc << "EOF"
#!/bin/bash
# VERSION: 20031029.0025
#
# Comprime (con bzip2 o gzip) todas las páginas de manual de una
# jerarquía y actualiza los enlaces simbólicos
# - Por Marc Heerdink <marc @ koelkast.net>
# Modificado por Mark Hymers <markh @ linuxfromscratch.org>
# para poder escojer entre ficheros gzip o bzip2 y tratar correctamente
# todos los enlaces simbólicos
#
# Modificado el 30/09/2003 por Yann E. Morin <yann.morin.1998 @ anciens.enib.fr>
# para aceptar compresión/descompresión, manejar correctamente enlaces
# duros, permitir el cambio de enlaces duros por blandos, especificar el nivel
# de compresión, procesar man.conf para todas las apariciones de MANPATH,
# permitir hacer copias de respaldo y permitir que se gu7arde la versión mas
# reciente de una página.
#
# TODO:
# - elegir el método de compresión por defecto basandose en la
# herramienta disponible : gzip o bzip2;
# - ofrecer una opción para elegir automáticamente el mejor método de
# compresión según la página (por ejemplo, comprobar página a página
# qué gzip/bzip2/lo que sea es mas efectivo);
# - cuando exista una variable de entorno MANPATH, utilizarla en vez de
# /etc/man.conf (útil para que los usuarios (des)compriman sus
# páginas de manual);
# - ofrecer una opción para recuperar una copia de respaldo anterior;
# - añadir otras herramientas de compresión (compress, zip, etc?).
# ¿Es necesario?
# Bastante divertido, esta función muestra algo de ayuda.
function help ()
{
if [ -n "$1" ]; then
echo "Opción desconocida : $1"
fi
( echo "Uso: $0 <metodo_de_compresion> [opciones] [dirs]" && \
cat << EOT
Donde metodo_de_compresion es uno de :
--gzip, --gz, -g
--bzip2, --bz2, -b
Comprime utilizando gzip o bzip2.
--decompress, -d
Descomprime las páginas de manual.
--backup Especifica que ha de hacerse un respaldo .tar para cada directorio.
En caso de que un respalde exista, es salvado como .tar.old antes
de hacer el nuevo respaldo. Si existe un respaldo .tar.old, este es
eliminado antes de salvar el respaldo.
En modo de respaldo no puede realizarse ninguna otra acción.
Y donde las opciones són :
-1 to -9, --fast, --best
El nivel de copmpresión, tal y como lo aceptan gzip y bzip2. Cuando
no se especifica, utiliza el nivel por defecto del método indicado
(-6 para gzip y -9 para bzip2). No se utiliza en los modos de
respaldo o descompresión.
--force, -F Fuerza la (re-)compresión, incluso si el anterior tenía el mismo
método. ütil cuando se cambia el nivel de compresión. Por defecto,
una página no es recomprimida si termina en el mismo sufijo que
que añade el método (.bz2 para bzip2, .gz para gzip).
--soft, -S Cambia enlaces duros por enlaces blandos. Usar con cuidado,
pues el primer fichero encontrado se usará como referencia. No se
utiliza en modo de respaldo.
--hard, -H Cambia enlaces blandos por enlaces duros. No se utiliza en
modo de respaldo..
--conf=dir, --conf dir
Especifica la localización de man.conf. Por defecto /etc.
--verbose, -v Modo detallado, muestra el nombre del directorio que se está
procesando. Dobla la opción para hecerle mas detallado y que muestre
el nombre del fichero que se está procesando.
--fake, -f Falsa ejecución. Muestra los parámetros actuales que se usarán.
dirs Una lista de rutas absolutas a los directorios man separadas por
espacios.
Cuando está vacio, y solo entonces, procesa todas las apariciones
de MANPATH en ${MAN_CONF}/man.
Notas sobre la compresión
Hubo una discusión en blfs-support sobre los niveles de compresión de
gzip y bzip2 en las páginas de manual, teniendo en cuenta el sistema de
ficheros anfitrión, la arquitectura, etc... Al final la conclusión fué que gzip
es mucho mas eficiente sobre ficheros "pequeños" y bzip2 sobre ficheros
"pequeños", siendo pequeño y grande muy dependiente del contenido de
los ficheros.
Mira el mensaje original de Mickael A. Peters, titulado "Bootable Utility CD",
y fechado 20030409.1816(+0200), y los mensajes siguientes:
http://linuxfromscratch.org/pipermail/blfs-support/2003-April/038817.html
En mi sistema (x86, ext3), las páginas de manual tenían 35564kiB antes
de comprimirlas. Comprimidas con gzip -9 bajaron a 20372kiB (57.28%),
con bzip2 -9 bajaron a 19812kiB (55.71%). Esto es un ahorro de espacio
del 1.57%. YMMV.
Lo que no se tuvo en consideración fué la velocidad de descompresión.
Pero, ¿esto tiene sentido?. U obtienes acceso rápido con página de manual
sin comprimir, o ganas espacio a expensas de un ligero retardo de tiempo.
Bien, mi P4-2.5GHz no llegó a percatarse de esto... :-)
EOT
) | less
}
# Esta función comprueba que la página de manual es idéntica entre las
# versiones bzip2, gzip y sin comprimir.
# $1 es el directorio en el que reside el fichero
# $2 es el nombre del fichero de la página de manual
# Devuelve 0 (verdadera) si el fichero es mas reciente y debe tenerse en cuenta,
# y 1 (falso) si el fichero no lo es (y por tanto debe borrarse)
function check_unique ()
{
# NB. Cuando hay enlaces duros a este fichero, estos no
# son borrados. De hecho, si hay enlaces duros, todos ellos
# tienen la misma fecha/hora, lo que los deja preparados para
# borrarlos mas adelante.
# Construye la lista con todas las páginas de manual que tienen
# el mismo nombre
DIR=$1
BASENAME=`basename "${2}" .bz2`
BASENAME=`basename "${BASENAME}" .gz`
GZ_FILE="$BASENAME".gz
BZ_FILE="$BASENAME".bz2
# Busca y guarda la mas reciente
LATEST=`(cd "$DIR"; ls -1rt "${BASENAME}" "${GZ_FILE}" "${BZ_FILE}" 2>/dev/null | tail -n 1)`
for i in "${BASENAME}" "${GZ_FILE}" "${BZ_FILE}"; do
[ "$LATEST" != "$i" ] && rm -f "$DIR"/"$i"
done
# En caso de que el fichero especificado sea el mas nuevo, devuelve 0
[ "$LATEST" = "$2" ] && return 0
# Si el fichero no es el mas nuevo, devuelve 1
return 1
}
# OK, procesa los argumentos de la línea de comandos e inicializa un estado
# algo sensible, esto es : no cambia el estado de los enlaces, procesa
# /etc/man.conf, es mas silencioso, busca man.conf en /etc, y no fuerza la
# (re-)compresión.
COMP_METHOD=
COMP_SUF=
COMP_LVL=
FORCE_OPT=
LN_OPT=
MAN_DIR=
VERBOSE_LVL=0
BACKUP=no
FAKE=no
MAN_CONF=/etc
while [ -n "$1" ]; do
case $1 in
--gzip|--gz|-g)
COMP_SUF=.gz
COMP_METHOD=$1
shift
;;
--bzip2|--bz2|-b)
COMP_SUF=.bz2
COMP_METHOD=$1
shift
;;
--decompress|-d)
COMP_SUF=
COMP_LVL=
COMP_METHOD=$1
shift
;;
-[1-9]|--fast|--best)
COMP_LVL=$1
shift
;;
--force|-F)
FORCE_OPT=-F
shift
;;
--soft|-S)
LN_OPT=-S
shift
;;
--hard|-H)
LN_OPT=-H
shift
;;
--conf=*)
MAN_CONF=`echo $1 | cut -d '=' -f2-`
shift
;;
--conf)
MAN_CONF="$2"
shift 2
;;
--verbose|-v)
let VERBOSE_LVL++
shift
;;
--backup)
BACKUP=yes
shift
;;
--fake|-f)
FAKE=yes
shift
;;
--help|-h)
help
exit 0
;;
/*)
MAN_DIR="${MAN_DIR} ${1}"
shift
;;
-*)
help $1
exit 1
;;
*)
echo "\"$1\" no es el nombre absoluto de una ruta"
exit 1
;;
esac
done
# Redirecciones
case $VERBOSE_LVL in
0)
# O, silencioso
DEST_FD0=/dev/null
DEST_FD1=/dev/null
VERBOSE_OPT=
;;
1)
# 1, algo detallado
DEST_FD0=/dev/stdout
DEST_FD1=/dev/null
VERBOSE_OPT=-v
;;
*)
# 2 y superiores, es mas detallado
DEST_FD0=/dev/stdout
DEST_FD1=/dev/stdout
VERBOSE_OPT="-v -v"
;;
esac
# Nota: en mi máquina, 'man --path' muestra /usr/share/man duplicado,
# una vez con '/' al final, y otra si él.
if [ -z "$MAN_DIR" ]; then
MAN_DIR=`man --path -C "$MAN_CONF"/man.conf \
| sed 's/:/\\n/g' \
| while read foo; do dirname "$foo"/.; done \
| sort -u \
| while read bar; do echo -n "$bar "; done`
fi
# Si no hay MANPATH en ${MAN_CONF}/man.conf, aborta el proceso
if [ -z "$MAN_DIR" ]; then
echo "Directorio no especificado y no encontrado con \`man --path'"
exit 1
fi
# ¿Falsa ejecución?
if [ "$FAKE" != "no" ]; then
echo "Parámetros actuales usados:"
echo -n "Compresión.......: "
case $COMP_METHOD in
--bzip2|--bz2|-b) echo -n "bzip2";;
--gzip|__gz|-g) echo -n "gzip";;
--decompress|-d) echo -n "descompresión";;
*) echo -n "desconocido";;
esac
echo " ($COMP_METHOD)"
echo "Nivel de compresión.: $COMP_LVL"
echo "Sufijo de compresión: $COMP_SUF"
echo -n "Compresión forzada.: "
[ "foo$FORCE_OPT" = "foo-F" ] && echo "si" || echo "no"
echo "man.conf is.......: ${MAN_CONF}/man.conf"
echo -n "Enlaces duros........: "
[ "foo$LN_OPT" = "foo-S" ] && echo "convertir en blandos" || echo "dejarlos así"
echo -n "Enlaces blandos........: "
[ "foo$LN_OPT" = "foo-H" ] && echo "convertir en duros" || echo "dejarlos así"
echo "Respaldo............: $BACKUP"
echo "Falsa ejecución (!si!).....: $FAKE"
echo "Directorios.......: $MAN_DIR"
echo "Nivel de detalles...: $VERBOSE_LVL"
exit 0
fi
# Si no se especifica un método, mostrar la ayuda
if [ -z "${COMP_METHOD}" -a "${BACKUP}" = "no" ]; then
help
exit 1
fi
# En modo respaldo, hace solo el respaldo
if [ "$BACKUP" = "yes" ]; then
for DIR in $MAN_DIR; do
cd "${DIR}/.."
DIR_NAME=`basename "${DIR}"`
echo "Backing up $DIR..." > $DEST_FD0
[ -f "${DIR_NAME}.tar.old" ] && rm -f "${DIR_NAME}.tar.old"
[ -f "${DIR_NAME}.tar" ] && mv "${DIR_NAME}.tar" "${DIR_NAME}.tar.old"
tar cfv "${DIR_NAME}.tar" "${DIR_NAME}" > $DEST_FD1
done
exit 0
fi
# Sé que MAN_DIR solo contiene rutas absolutas.
# Necesito tener en cuenta las páginas de manual localizadas, por lo
# que lo hago recursivamente.
for DIR in $MAN_DIR; do
MEM_DIR=`pwd`
cd "$DIR"
for FILE in *; do
# Corrige el caso en el que los directorios están vacios.
if [ "foo$FILE" = "foo*" ]; then continue; fi
# Corrige el caso en el que los enlaces duros ven el cambio en su esquema
# de compresión (de sin comprimir a comprimidas, o de bzip2 a gzip o de
# gzip a bzip2). También corrige el caso en el que hay presentes mútilples
# versiones de la página, que pueden estar comprimidas o no.
if [ ! -L "$FILE" -a ! -e "$FILE" ]; then continue; fi
# No comprime los ficheros whatis
if [ "$FILE" = "whatis" ]; then continue; fi
if [ -d "$FILE" ]; then
cd "${MEM_DIR}" # Regresa a donde ejecutamos "$0", en caso de que "$0"=="./compressdoc" ...
# Vamos recursivamente a este directorio
echo "-> Entrando a ${DIR}/${FILE}..." > $DEST_FD0
# No necesito usar --conf, pues especifico el directorio de trabajo.
# Pero necesito salir en caso de error.
"$0" ${COMP_METHOD} ${COMP_LVL} ${LN_OPT} ${VERBOSE_OPT} ${FORCE_OPT} "${DIR}/${FILE}" || exit 1
echo "<- Saliendo de ${DIR}/${FILE}." > $DEST_FD1
cd "$DIR" # Necesario para la siguiente iteración del bucle.
else # !dir
if ! check_unique "$DIR" "$FILE"; then continue; fi
# Comprueba si el fichero ya está comprimido con el método especificado
BASE_FILE=`basename "$FILE" .gz`
BASE_FILE=`basename "$BASE_FILE" .bz2`
if [ "${FILE}" = "${BASE_FILE}${COMP_SUF}" -a "foo${FORCE_OPT}" = "foo" ]; then continue; fi
# Si tenemos un enlace simbólico.
if [ -h "$FILE" ]; then
case "$FILE" in
*.bz2)
EXT=bz2 ;;
*.gz)
EXT=gz ;;
*)
EXT=none ;;
esac
if [ ! "$EXT" = "none" ]; then
LINK=`ls -l "$FILE" | cut -d ">" -f2 | tr -d " " | sed s/\.$EXT$//`
NEWNAME=`echo "$FILE" | sed s/\.$EXT$//`
mv "$FILE" "$NEWNAME"
FILE="$NEWNAME"
else
LINK=`ls -l "$FILE" | cut -d ">" -f2 | tr -d " "`
fi
if [ "$LN_OPT" = "-H" ]; then
# Cambia este enlace blando por uno duro
rm -f "$FILE" && ln "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
chmod --reference "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
else
# Mantiene este enlace como blando.
rm -f "$FILE" && ln -s "${LINK}$COMP_SUF" "${FILE}$COMP_SUF"
fi
echo "Reenlazando $FILE" > $DEST_FD1
# En cambio, si tenemos un fichero plano.
elif [ -f "$FILE" ]; then
# Tiene en cuenta los enlaces duros: contruye la liste de ficheros enlazados
# al que vamos a (des)comprimir.
# NB. Esto no es óptimo pues el fichero será comprimido eventualmente
# tantas vecese como enlaces duros tenga. Pero por ahora es la forma
# mas segura.
inode=`ls -li "$FILE" | awk '{print $1}'`
HLINKS=`find . \! -name "$FILE" -inum $inode`
if [ -n "$HLINKS" ]; then
# ¡Tenemos enlaces duros! Los elimina ahora.
for i in $HLINKS; do rm -f "$i"; done
fi
# Ahora tiene en cuanta los ficheros sin enlaces duros.
# Los descomprimimos primero para comprimirlos mas tarde
# con el nivel de compresión seleccionado...
case "$FILE" in
*.bz2)
bunzip2 $FILE
FILE=`basename "$FILE" .bz2`
;;
*.gz)
gunzip $FILE
FILE=`basename "$FILE" .gz`
;;
esac
# Comprime el fichero con el nivel de compresión indicado, si es necesario.
case $COMP_SUF in
*bz2)
bzip2 ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}"
echo "Comprimiendo $FILE" > $DEST_FD1
;;
*gz)
gzip ${COMP_LVL} "$FILE" && chmod 644 "${FILE}${COMP_SUF}"
echo "Comprimiendo $FILE" > $DEST_FD1
;;
*)
echo "Sin comprimir: $FILE" > $DEST_FD1
;;
esac
# Si el fichero tiene enlaces, los regenera (tanto duros como blandos)
if [ -n "$HLINKS" ]; then
for i in $HLINKS; do
NEWFILE=`echo "$i" | sed s/\.gz$// | sed s/\.bz2$//`
if [ "$LN_OPT" = "-S" ]; then
# Hace este enlace duro uno blando.
ln -s "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF"
else
# Mantiene el enlace duro como tal.
ln "${FILE}$COMP_SUF" "${NEWFILE}$COMP_SUF"
fi
chmod 644 "${NEWFILE}$COMP_SUF" # En realidad solo funciona con
# enlaces duros. Inofensivo con
# enlaces blandos.
done
fi
else
# Hay un problema cuando no obtenemos un enlace o un fichero plano.
# Obviamente, nunca deberíamos llegar aquí... :-(
echo "Whaooo... \"${DIR}/${FILE}\" no es un enlace o un fichero plano. Compruebalo:"
ls -l "${DIR}/${FILE}"
exit 1
fi
fi
done # para FILE
done # para DIR
EOF
chmod 755 /usr/bin/compressdoc |
Ahora, como root, puedes ejecutar /usr/bin/compressdoc --bz2 para comprimir todas las páginas de manual de tu sistema. También puedes ejecutar /usr/bin/compressdoc --help para obtener una ayuda clara sobre lo que el guión puede hacer.
No olvide que algunos programas, como el sistema X Window o XEmacs, también instalan su documentación en lugares no estándares (como /usr/X11R6/man, etc...). No olvides añadir estas localizaciones al fichero /etc/man.conf con una sección MANPATH=/ruta.
Ejemplo:
...
MANPATH=/usr/share/man
MANPATH=/usr/local/man
MANPATH=/usr/X11R6/man
MANPATH=/opt/qt/doc/man
... |
Generalmente, los sistemas de instalación de paquetes no comprimen las páginas man/info, lo que significa que necesitarás ejecutar este guión otra vez si quieres mantener el tamaño de tu documentación tan pequeño como sea posible. Igualmente, ten en cuenta que es seguro ejecutar el guión tras actualizar un paquete: cuando tienes varias versiones de una página (por ejemplo, una comprimida y otra sin comprimir) la mas reciente es la que se guarda y las otras borradas..