Archivo de Etiquetas de 'linux'

Página 2 de 3

Programmed shutdown: pequeño script para apagar la máquina

Programmed shutdown: step 1

Paso 1: ¿cuánto tiempo?

Después de buscar (no, mucho, eso si :D ) por Google y no encontrar algo que se adaptase a mis mínimas necesidades, me he hecho un pequeño script de apagado de la máquina para mi maravilloso PC en el salón (que no de salón :) ) equipado con un GNU/Linux (en concreto una Debian, pero el script es multiversal dentro del mundo Linux :-P y quizá Unix, depende de si el software zenity está en otras plataformas o no).

Programmed shutdown: step 2

Paso 2: tú tranqui, que ya te aviso yo...

La idea es poder pedirle a la máquina que se apague dentro de equis minutos, con posilibidad de cancelarlo y cierto feedback visual de cuánto tiempo te queda. Posibles usos son por ejemplo imitar la función Sleep de algunas televisiones, o, cuando te vas de vacaciones y tienes algunas descargas tirando, o algún programa de TV que quieres que se grabe, pedirle que se apague en unos días para no consumir energía tontamente.

El script sólo requiere que esté instalado Zenity. El código fuente del mismo lo podéis ver a continuación:

#!/bin/bash
# Ask for time in minutes to sleep and ater that poweroff the computer
# needs - zenity
# Diego Toharia - deigote@deigote.com

# Messages
TITLE="Apagar el ordenador"
MINUTES_QUESTION="¿Dentro de cuántos minutos?"
WAIT_PRE="Esperando"
WAIT_POST="minutos"

minutes=`zenity --entry --title "$TITLE" --text "$MINUTES_QUESTION" 2>&1` || exit
seconds=`expr $minutes "*" 60`

if [ $seconds != "" ] ; then
	for i in `seq 1 $seconds` ; do
		percentage=`expr $i "*" 100`
		percentage=`expr $percentage "/" $seconds`
		echo $percentage
		sleep 1
	done | zenity --title="$TITLE" --text="$WAIT_PRE $minutes $WAIT_POST" --progress --auto-close --auto-kill
	poweroff
fi

También quiero pensar que, si alguna vez cambio algo, podréis encontrar una versión actualizada en el enlace Programmed shutdown script pero no garantizo que cumpla mis propósitos :-D .

Programmed shutdown: laucher

Programmed shutdown: laucher

Para invocarlo, basta guardarlo en un directorio que esté en el path (yo suelo usar para estos scripts $HOME/bin) y darle permisos de ejecución. Recordar que debéis tener permisos para ejecutar el mandato poweoff. En mi caso, tengo en la barra inferior un lanzador precedido del mandato gksudo, de tal manera que el script se lanza con los permisos necesarios, pidiéndome la contraseña en caso necesario.

Mini tutorial de awk

Por petición popular, voy a escribir un poco sobre un mandato típico de los sistemas operativos UNIX (apareció por primera vez en 1977 nada menos), awk.

awk es un mandato que sirve para procesar líneas de texto (separadas, naturalmente, por un salto de línea). awk cuenta con un pequeño y sencillo lenguaje de programación que es interpretado (no necesita ser compilado), y resulta tremendamente útil cuando queremos extraer información de extensos campos de texto (y, posiblemente, manipularla).

El funcionamiento del madato awk es muy sencillo: basicamente tenemos dos posiblidades:

$ awk -f fuente.awk fichero_entrada.txt
$ awk 'fragmento de código fuente' fichero_entrada.txt

En la primera de ellas, el código fuente está en un fichero (recomendado para usos que vayan a repetirse con el tiempo y con códigos fuentes largos) mientras que el segundo ofrece la ventaja de poder poner el código fuente como un argumento más. Esto es muy útil para el uso de awk en scripts o similares, en los que el uso de ficheros puede ser un engorro. También cabe la posibilidad de omitir el fichero de entrada, en cuyo caso awk leerá de la entrada estándar.

Respecto al lenguaje awk, tiene una estructura similar a lo siguiente:

BEGIN { acción }
/patrón/ { acción }
END { acción }

La forma de funcionamiento la siguiente:

  1. Nada más comenzar la ejecución, se evaluará la acción marcada entre llaves precedida por la palabra reservada BEGIN.
  2. Por cada campo de texto (recordemos, por defecto líneas) awk evaluará si se ajusta al patrón (una expresión regular), y de ser así, ejecutará la acción marcada entre llaves que sigue a dicho patrón. Por cada líneas se evaluarán todos los patrones a menos que en una de las acciones ejecutadas se encuentre la orden next, en cuyo caso se comenzará desde el principio con la siguiente línea.
  3. Finalmente, se procesará la acción marcada entre llaves precedida por la palabra reservada END.

Respecto a los patrones de awk, son, como ya he dicho, expresiones regulares. No voy a explicar aquí todas las posiblidades porque no acabaría nunca (y con la ayuda de la Wikipedia os debería bastar), basten un par de ejemplos:

  • /[afP]MEMOLO[1-3]z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO seguidas de un dígito comprendido del 1 al 3 y seguida por la letra z.
  • /[afP](MEMOLO)+([1-3])*z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO una o varias veces seguidas de un dígito comprendido del 1 al 3 que puede aparecer ninguna, una, o varias veces y seguida por la letra z.

Esta es la parte más complicada de awk (ya sabeis lo que se dice de las expresiones regulares).

En cuanto a las acciones, cualquiera que haya programado en C no tendrá mucho problema, ya que es similar. Como características cabría destacar:

  • El acceso a las línea actual se hace mediante unas variables especiales. En concreto $0 referencia a toda la línea mientras que $1, $2, etcétera, referencian a los campos de dicha línea. El separador de campos por defecto es un espacio o un tabulador, pudiéndose modificar en la acción de BEGIN con la variable FS (otra expresión regular, por cierto).
  • No es necesario declarar ni tipar las variables, cuyo formato es el mismo que en C (su expresión regular, para que vayais practicando, es algo parecido a [a-Z]([a-Z] | [1-9] | _ )*).
  • Están permitidas todas las estructuras clásicas de programación en un formato estilo C (bucles, expresiones condicionales, operadores, etcétera).
  • Para imprimir resultados, existen dos posiblidades. La primera, print, es la más cómoda, puesto que no es necesario usar paréntesis para sus argumentos y cuenta con concatenación automática de los mismos (algo parecido al mandato echo de la terminal. Por ejemplo, print “la línea ” $0 “tiene ” NF ” palabras” imprimirá la frase que precede a print sustituyedo $0 por la línea actual y NF (otra variable especial) por el número de campos de la misma. Como segunda posibilidad, tenemos printf, que ofrece mayor control (es idéntico al del lenguaje C).

¿Y qué pasa con los los jugosos ejemplos? Pues he recopilado alguno que otro según me ha ido surgiendo la necesidad de usarlo estos días.

  • Por ejemplo, el otro día necesitaba obtener del fichero de log de Tomcat las líneas que contuviesen o bien “SOAP21″ o bien ” – 2 “. Esto sería sencillo de hacer con dos grep, pero yo necesitaba que esas líneas mantuviesen el orden en el que habían aparecido en el fichero, y hacer eso con un grep requiere de una expresión regular bastante más compleja de lo que en realidad es necesario. Además, quería saber en qué número de línea del fichero estaba cada línea buscada. Con awk, fue tan sencillo como esto:
    cat tomcat.log | awk '/SOAP21/{print NR " - " $0} / - 2/{print NR " - "$0}'
  • También necesité, en el mismo fichero, verificar que se cumpliese una secuencia, y concretamente, me valía saber que, dentro del conjunto de líneas que contenían “SOAP21″, las múltiplo de 5 eran idénticas, ya que de esta manera sabía que se habían cumplido todos los pasos. Por lo tanto, necesitaba sacar las líneas que tuviesen “SOAP21″, y dentro de éstas, sólo las que su número de línea fuese múltiplo de 5. Nuevamente, awk te lo pone fácil:
    cat tomcat.log | awk 'BEGIN { nl = 1 } /SOAP21/ { if (nl % 5 == 0) print ; nl++}'
  • En plan más “complicado” (teniendo en cuenta que lo de antes era trivial), hice una pequeña línea para sacar la nota media a partir del archivo html que te devuelve la UPM cuando consultas tu expendiente usando la modalidad “Último estado de cada asignatura” (aunque falla cuando tienes alguna matrícula, pero bueno, eso no es lo importante ahora). El código es el siguiente:
    cat consulta.upm.html | grep "
    /<\/table>/ { d = 0 } { if (d > 0) { if (c == 10) { print ; c = 0 } else c++ } }' | grep
    '>\([1-9][0-9]\|[1-9]\|[1-9]\,[0-9]\{1\}\|[1-9]\,[0-9]\{2\}\)<' | cut -d 1 -f2 -d'>' | cut
    -f1 -d'<' | awk 'BEGIN { t=0.0;n=0; } {print ; t=t+$1 ; n++} END { print "Total " t "
    Asignaturas " n " Media " t/n}'

    Como veis, el primer fragmento de awk hace una selección de líneas, imprimiendo sólo las filas de las tablas que sean múltiplo de 10 (son en las que se encuentran las notas) y que estén contenidas entre una línea que tenga la palabra Obs y el primer final de tabla en html. Una vez obtenidas estas líneas, uso grep para quedarme solo con las que tienen nota y cut para dejar sólo la nota, quitando el resto de elementos html. El segundo fragmento de awk se encarga de ir sumando las notas y el número de asignaturas para imprimir la media.
  • EDITO: iré añadiendo más fantabulosos ejemplos ;-) según me los vaya encontrado.

  • Mi hermano el otro día me preguntó como resolvería un problema y le sugerí que usara awk. El problema consistía en que tenía ficheros (por cierto, de más de 80.000 líneas) con una estructura tal que
    frase1 1
    frase2 5
    ...
    fraseN M

    y quería sumar los números de cada frase. En el caso original tenía la ventaja de que las frases siempre iban en el mismo orden en todos los ficheros, pero la sencillez de awk hace que la solución (que corre a cargo de mi hermano, por cierto) valga para casos que no estén en orden (e incluso que aparezcan frases en algunos ficheros y en otros no). Además, se requería que fuese relativamente rápido, y awk cumplió con las expectativas (la solución previa eran pruebas con scripts más o menos a mano y los resultados se iban por encima de los 10 minutos, frente a los 2 minutos de la solución con awk). El único problema era juntar la salida de los ficheros, pero awk permite trabajar con varios ficheros de entrada de datos (si no, un poquito de bash scripting, for i in *.out ; do cat $i ; done, lo hubiese solucionado). Los ficheros tenían extensión .out, por lo que la solución final es:
    awk 'BEGIN { FS = " ";} { resultados[$1] += $2 } END { for(category in resultados) print category, resultados[category]; } *.out'
    Como veis es sencillo, limpio y eficaz :-D ¡con awk, la suciedad se va en un bang! Aquí además podeis ver algunas cosas más de awk, como los bucles, los array (estilo PHP, sin declaración ni reserva de memoria ni inicialización de datos) y la variable especial FS, que sirve para especificar cómo separar los campos de una línea (aunque en este caso no haga falta porque por defecto es espacio o tabulador).

Y esto es todo por hoy. Huelga decir que en Internet encontrareis cientos de ejemplos y tutoriales, pero yo quería hacer una pequeña introducción con un par de ejemplos más prácticos que los que suelo encontrar (al menos, serían prácticos para mí ;-)). Espero que os sea de utilidad.

Webcam Quickcam Messenger en Ubuntu Linux

Pues sí, como he comentado en el post anterior, uno de los reyes (no recuerdo si Melchor o Baltasar… Gaspar no, que ese me ha traido la minimoto) me ha traido una webcam, que he hecho funcionar bajo Linux (concretamente, yo uso Ubuntu). La cuestión es que oficialmente la cámara no está soportada. Sin embargo encontré un driver, enlazado ya en Del.ici.us, que es el siguiente:
Quickcam Messenger Driver
Tras compilarlo y tal, la cosa funcionó, ya he hecho mis primeros videochateos con el Amsn (¡como mola! :D). El único problema que tengo es que la resolución es pobre (lei por ahí que de momento no soporta los 640×480 de la cámara) y que cada vez que reconecto la cámara, tengo que borrar y cargar los drivers de nuevo (puede ser problema de que antes instalé otros drivers y que estén todos, los de Ubuntu incluidos, pegándose por la cámara :P), pero bueno, al final se resume en:
# sudo rmmod quickcam ; sudo rmmod videodev ; sudo modprobe quickcam ; sudo modprobe videodev
cada vez que conecto la cámara. El micro parece que es detectado por la Ubuntu (de hecho, me monta la cámara como una tarjeta de sonido extra), pero todavía no he conseguido grabar nada con él (tampoco he dedicado mucho tiempo).

Technorati Tags:

Firewalling/accounting con iptables, averiguar la IP y algunas cosas más

Bueno. Creo que ya va tocando un poco de iptables, mi tema linuxero favorito :P. Pues nada, simplemente después de cierta pereza me he decidido a hacer un “firewall” con iptables para mi máquina. Pongo “firewall” entre comillas porque no hago filtrado en absoluto: estoy detrás del router, así que pocos ataques recibo. Encima los switches que comunican mis PC’s , al ser precisamente switches y no hub’s, separan los dominios de colisión y no recibo trafico ethernet de ninguna otra máquina. En fin, que no hay lugar para mucha experimentación. Sin embargo, un amante de las estadísticas de red como yo no puede dejar pasar la ocasión que brinda iptables de contar todo el tráfico que pasa por mi PC , por lo que he hecho el siguiente firewall, que pongo a continuación a trozos para comentar el propósito de cada cosa.

  • Para empezar, algunas variables. El nombre del script, la localización del mandato iptables, el puerto que uso para el emule y los puertos que uso para el bittorrent. Poca cosa :):
    
    #!/bin/sh
    # An extended firewall script.
    # Diego Toharia
    
    # Some vars
    N=/etc/init.d/firewall
    IPTABLES=/sbin/iptables
    EMULE_PORT=6889
    BT_PORT=6881:6888
    
  • Aquí esta la chicha de iptables. Las reglas, metidas dentro de una función. Como se puede ver hay poca cosa, y ni una sola acción de salto (-j, jump ). Así, por cada regla sólo se cuentan los paquetes que enlazan con la misma. Si quisíeramos filtrar alguna de ellas, añadimos -j DROP y listo :). Principalmente lo que hago es, primeramente, crear contadores de conexiones entrantes (es decir, el número de paquetes/bytes que generan las nuevas conexiones de clientes a programas con socket en estado LISTEN o en escucha), y luego añado varios contadores del tráfico generado tanto entrante como saliente por el emule, bittorrent, web, y globales (dentro y fuera de la LAN y en total). Como ya he comentado, no hay mucho más, ya que es una máquina detrás de un router y que no es router a su vez:
    
    # Rules definitions
    rules_def() {
        ############ CONNECTIONS COUNTERS ##################################
        # Count Emule connections
        $IPTABLES -A INPUT -m state --state NEW -p tcp --dport $EMULE_PORT
        # Count Bittorrent connections
        $IPTABLES -A INPUT -m state --state NEW -p tcp --dport $BT_PORT
        # Count Ssh connections
        $IPTABLES -A INPUT -m state --state NEW -p tcp --dport ssh
        # Count Http connections
        $IPTABLES -A INPUT -m state --state NEW -p tcp --dport http
        ############ TRAFIC COUNTERS #######################################
        # Count Emule input traffic
        $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED         -p tcp --dport $EMULE_PORT
        # Count Bittorrent input traffic
        $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED         -p tcp --dport $BT_PORT
        # Count Http traffic
        $IPTABLES -A INPUT  -p tcp --sport http
        $IPTABLES -A OUTPUT -p tcp --dport http
        # Count LAN traffic
        $IPTABLES -A INPUT -s 192.168.0.0/24
        $IPTABLES -A OUTPUT -d 192.168.0.0/24
        # Count inet traffic
        $IPTABLES -A INPUT -s ! 192.168.0.0/24
        $IPTABLES -A OUTPUT -d ! 192.168.0.0/24
        # Count all traffic
        $IPTABLES -A INPUT
        $IPTABLES -A OUTPUT
        ####################################################################
    }
    
  • Aquí pongo una función que averigua cuál es la dirección IP con la que navegamos por Internet, y cuales son las direcciones IP configuradas en nuestra máquina. Para hacerla, he usado la información del siguiente enlace: http://blog.enrique.barbeito.org/. Lo he encontrado usando Google, como no. Muchas gracias a Enrique Barbeito y su blog.
    
    # IP finder
    ipfinder() {
            IP_PUB=`lynx -dump www.cualesmiip.net | grep Tu | awk '{print $5}'`
            IP_PRIVS=`ifconfig | grep "inet addr" | cut -f2 -d: | cut -f1 -d' '`
            export IP_PUB=$IP_PUB
            export IP_PRIV=$IP_PRIVS
            echo "Public IP"
            echo $IP_PUB
            echo "Private IPs"
            echo $IP_PRIVS
    }
    
  • A continuación hago una función que, a partir de información guardada por el resto del script, calcula unas tasas de transferencia desde que se puso en marcha el script hasta que se paró (siempre que estas operaciones se hagan de forma correcta, es decir, arrancando y parando el script con las propias opciones del script). Esta funcionalidad, es, sin duda, la que más me gusta :P, todos los días consulto el trafico del dia anterior y me congratulo, jejeje:
    
    # Traffic rates
    traffic_rates() {
        START_TIME=`cat /var/run/firewall.start`
        FINISH_TIME=`cat /proc/uptime | awk '{print $1}' | cut -d'.' -f 1`
        UPTIME=`expr $FINISH_TIME - $START_TIME`
        INPUT_TRAFFIC=`sudo iptables -L INPUT -v -x | grep \!localnet | awk '{print $2}'`
        INPUT_RATE=`expr $INPUT_TRAFFIC / 1024 / $UPTIME`
        OUTPUT_TRAFFIC=`sudo iptables -L OUTPUT -v -x | grep \!localnet | awk '{print $2}'`
        OUTPUT_RATE=`expr $OUTPUT_TRAFFIC / 1024 / $UPTIME`
        echo "Input rate: $INPUT_RATE KB/s (`expr $INPUT_TRAFFIC / 1048576` MB)"
        echo "Output rate: $OUTPUT_RATE KB/s (`expr $OUTPUT_TRAFFIC / 1048576` MB)"
    }
    
  • Por último, el “programa principal” del script. Está hecho a modo de script de los del init.d, para ser arrancado por el mismo (luego explicaré cómo hacerlo). Se encarga de coordinar lo anterior para, por cada start y stop, guardar en un log el accounting, la direccion IP , y las tasas de tráfico del intervalo de tiempo entre los mismos:
    
    case "$1" in
      start)
            cat /proc/uptime | awk '{print $1}' | cut -d'.' -f 1             > /var/run/firewall.start
            echo "Firewall: setting up iptables rules.."
            echo "###############################################"             > /var/run/firewall
            echo -n "Traffic from " >> /var/run/firewall
            date +%k:%M" of "%A' '%D >> /var/run/firewall
            rules_def
            ipfinder >> /var/run/ipfinder
            ;;
        stop)
            echo "Firewall: saving counters.."
            echo -n "To " >> /var/run/firewall
            date +%k:%M" of "%A' '%D >> /var/run/firewall
            echo "###############################################"             >> /var/run/firewall
            iptables -L -v >> /var/run/firewall
            echo "###############################################"             >> /var/run/firewall
            ipfinder >> /var/run/firewall
            echo "###############################################"             >> /var/run/firewall
            traffic_rates >> /var/run/firewall
            echo "###############################################"             >> /var/run/firewall
            mv /var/run/firewall /var/log/firewall/log.`date +%d_%m_%y_%H_%M`
            echo "Firewall: flushing iptables rules.."
            iptables -F
            iptables -X
            rm /var/run/ipfinder
            rm /var/run/firewall.start
            ;;
        reload|restart|force-reload)
            $N stop
            $N start
            ;;
      *)
            echo "Usage: $N {start|stop|restart|force-reload}" >&2
            exit 1
            ;;
    esac
    
    exit 0
    

Si poneis cada parte del código seguida, tendreis el script completo. Durante la ejecución del mismo podeis encontrar vuestra ip en el fichero /var/run/ipfinder, quedando los logs almacenados en el directorio /var/log/firewall que previamente debeis crear. Poniendo este fichero en /etc/init.d/ con el nombre firewall y ejecutando rcconf, o el mandato update_rec.d firewall defaults, lo tendreis todo funcionando, y podreis disponer de unas sencillas estadísticas para los que no queremos complicarnos la vida (para los que si quieran, a conjugar iptables con ntop, que me ha parecido potentisimo, y snort, que no lo he usado más que como sniffer pero es un potente detector de intrusos). Sigo buscando cómo hacer accounting del resto de máquinas, ya que aunque ponga la interfaz en modo promiscuo, iptables no procesa el tráfico que llega de otros PC’s . Mis posteriores descubrimientos, aquí, en próximas ediciones ;). No puedo terminar el artículo sin agradecer a Oskar Andreasson su magnifico trabajo con el tutorial de iptables, con el que yo me inicie y que es mi referencia para este tema.

Por supuesto, sólo para Linux.