auditd

auditd es una herramienta que pemite registrar llamadas a sistema y cambios en ficheros. Por ejemplo…

  • señales de terminación (auditctl -a exit,always -F arch=b64 -S kill)
  • cambios en pemisos de fichers (auditctl -w /etc/shadow -p wr -k private-shadow
  • ejecución de programas de un usuario concreto (auditctl -a exit,always -F arch=b64 -F uid=1001 -S execve)

Por defecto, el registro se guarda en /var/log/audit/audit.log

El comando ausearch permite buscar en dicho registro.

Cómo comprimir en paralelo en Debian

Paralelismo en el compresor

De momento, la opción -T de xz no está activa, con lo cual hay que recurrir a las versiones paralelas de los clásicos: pigz o pbzip2.

Una vez instalado, basta con especificar el compresor en los parámetros de tar (normalmente, estos comandos paralelos detectan los cores disponibles, con lo cual no hace falta especificar nada):

tar cf test.tar.bz2 -I pbzip2 test

Paralelismo en los trabajos

Para comprimir muchos ficheros, una solución obvia es comprimir varios a la vez. Esto sólo requiere alguna herramienta que reparta los ficheros entre los compresores. Gnu parallel viene como anillo al dedo:

# 2 ejemplos del manual
# comprimir todos los ficheros "*.html"
parallel gzip ::: *.html
# convertir todos los "*.wav" en mp3 con LAME
parallel lame {} -o {.}.mp3 ::: *.wav

# comprimir con xz todos los ficheros del listado "files",
# usando un máximo de 4 cores:
parallel -P 4 xz < files

Recuperar ficheros borrados de un sistema de ficheros ext3 ext4

Lo primero, detener todas las posibles escrituras.

Reiniciar con un Live CD, por ejemplo el estupendo Kali Linux (que además incluye extundelete).

Hacer una imagen de la partición (o volumen) de la que se quieren recuperar los datos. La imagen se puede guardar en otra partición, en un disco externo, en otro ordenador…

Después, se puede pasar a intentar recuperar los ficheros a partir de la imagen, con herramientas como extundelete:

extundelete --recover-all imagen.img

extundelete ofrece opciones para concretar el qué intentar recuperar (y así ahorrar algo de tiempo)

Obviamente, lo suyo es recuperar de una copia de seguridad (backup), pero no siempre es posible…

Instalar x2go server en Debian desde código fuente

El primer paso es sencillo:

# compilar el paquete x2goserver
cd /usr/local/src
wget http://code.x2go.org/releases/source/x2goserver/x2goserver-4.0.1.19.tar.gz
tar xvfz x2goserver-4.0.1.19.tar.gz 
cd x2goserver-4.0.1.19/
make -j 8 
make install

La mayoría de las dependencias del servidor están disponibles como paquetes Debian estándar:

apt-get install libc6 lsof bc openssh-server openssh-client libconfig-simple-perl pwgen libdbd-pg-perl libdbd-sqlite3-perl libfile-basedir-perl libcapture-tiny-perl adduser xauth psmisc net-tools sshfs x11-apps x11-session-utils x11-utils x11-xfs-utils x11-xkb-utils x11-xserver-utils fontconfig xinit xfonts-base x11-common libxml2  libpng12-0 libstdc++6 zlib1g libgcc1 libsys-syslog-perl libfile-which-perl

x2goserver no trae x2goagent. Si lo necesitas, lo puedes instalar (curiosamente, viene en el paquete nx-libs…):

# dependencias
apt-get install autoconf install libjpeg62-turbo-dev
wget http://code.x2go.org/releases/source/nx-libs/nx-libs_3.5.0.13-full.tar.gz
tar xvfz nx-libs_3.5.0.13-full.tar.gz 
cd nx-libs_3.5.0.13/
make -j 8
make install
cp bin/x2goagent /usr/local/bin
ln -s /usr/lib/NX3/bin/nxagent /usr/local/lib/x2go/x2goagent
# añadir /usr/lib/NX3/lib64/nx a LD_LIBRARY_PATH (por ejemplo, en /etc/bash.bashrc)

Si quieres disponer de un escritorio remoto y no está instalado (cosa habitual en servidores)… tendrás que instalarlo. Por ejemplo, Xfce (que tiene una buena relación prestaciones/”ligereza”):

apt-get install xfce4

En /tmp/.x2go-…./session.log se registran los mensajes de error al inicio de la sesión de x2go. Es un buen sitio para encontrar pistas de por qué no funciona… 😉

Registro en fichero del rendimiento del sistema

En Windows, para monitorizar en vivo el rendimiento bastan el Administrador de Tareas o el Monitor de Recursos.

Cuando la monitorización interactiva no resulta conveniente, podemos recurrir al Monitor de Rendimiento. Este monitor permite recopilar información de contadores de rendimiento en un fichero (al estilo “log”), para después analizarlo.

Los pasos a seguir son:

  1. En “Conjuntos de recopiladores de datos / Definido por el usuario”, crear un nuevo conjunto (bien a partir de una plantilla, o bien “manual”).
  2. Si no hemos definido una temporización / programación, ejecutar la recopilación (opciones “Iniciar” y “Detener”)
  3. Una vez finalizada la recopilación, podemos ir a “Informes / Definido por el usuario” y analizar la recopilación, bien en “modo texto” (“Ver / Informe”), o bien gráficamente (“Ver / Monitor de rendimiento”)

En las propiedades de un conjunto se pueden definir parámetros útiles, como: la ubicación del fichero de registro, la condición de parada de recopilación (por tiempo, por tamaño de fichero…), la programación de cuando realizar la recopilación…

Dentro de “conjunto de recopiladores”, podemos elegir uno de los recopiladores y, en “Propiedades”, definir qué contadores estarán activos y el intervalo de muestra, entre otros.

Analizar logs de atop con awk

Un sencillo script awk que analiza los logs de atop. A partir de aquí, el cielo es el límite 😉 (por ejemplo, adaptar la salida para generar gráficas con gnuplot)

#!/bin/bash
# Example of how to easily parse atop logs with awk
# You can adapt this to generate plots based on atop logs

# First collect the output of atop for each relevant file. For example:
#   for f in $(ls /var/log/atop/atop_2015*); do atop -r $f >> atop_collection; done
# Then pass that file (atop_collection) as stdin to this script
grep -v "^NET" - | awk 'BEGIN{summary=""; i=0}
                       /^ATOP/ {timestamp=$4 "-" $5; print timestamp " SYS " sys " USR " user " IRQ " irq " IDLE " idle " FREE " freemem " CACHE " cache; j=0; for (p in processes){print processes[j++]}; i=0; delete processes; next}
                       /^CPU/ {sys=$4; user=$7; irq= $10; idle=$13; next}
                       /^MEM/ {freemem=$7; cache=$10; next}
                       $1 ~ /[0-9]+/ {cpu=$11; sub(/%/,"",cpu); if(cpu+0 > 20){processes[i]=$0; i++}; next}
                       '

A partir del script anterior, se puede crear uno que resuma el consumo de memoria de cada comando:

#!/bin/bash
egrep -vi "^cpu|^mem|^atop|^prc|^swp|^pag|^net|^cpl|^  pid" - | grep -v 'since boot'  | awk 'BEGIN{summary=""; i=0}
{vsize_raw=$5; rsize_raw=$6; cmd=$10;
 
 vs_unit=substr(vsize_raw,length(vsize_raw),1);
 vsize=substr(vsize_raw,1,length(vsize_raw)-1);

 if(vs_unit == "M"){ vsize_scaled=vsize; }
 else if(vs_unit == "G") {vsize_scaled=vsize * 1024;}
 else {vsize_scaled=0};

 if(vsize_scaled > 300){
    if(vsizes[cmd] < vsize_scaled) vsizes[cmd] = vsize_scaled;
 }

 rs_unit=substr(rsize_raw,length(rsize_raw),1);
 rsize=substr(rsize_raw,1,length(rsize_raw)-1);

 if(rs_unit == "M"){ rsize_scaled=rsize; }
 else if(rs_unit == "G") {rsize_scaled=rsize * 1024;}
 else {rsize_scaled=0};

 if(rsize_scaled > 300){
    if(rsizes[cmd] < rsize_scaled) rsizes[cmd] = rsize_scaled;
 }

}END{
  for (k in vsizes){
      print k " " vsizes[k] " " rsizes[k];
  }
}'

A este script se le puede pasar directamente la salida de atop:

for f in $(ls /var/log/atop/atop_2015*); do atop -m -r $f; done | ./basic-atop-filter-cmd-mem 

Intérprete grub2

Grub2 ofrece una “intérprete de comandos” (shell) bastante “amigable”.

Con ls se puede ver el contenido de las particiones, con autocompletar:

ls (hd0,1)

Si usamos LVM, hay que cargar el módulo correspondiente. La sintaxis para referirse a un volumen pasa por mapper:

insmod lvm
set root=(hd0,1)
# o set root=/dev/mapper/vg1-os

Una vez ubicado el kernel y el initrd, se pueden especificar (también con autocompletar, siempre que la raíz esté bien especificada con el set root previo):

linux /vmlinuz-3.4.11
initrd /initrd-3.4.11.img

Finalmente, arrancamos Linux con

boot

Montar sistema de ficheros en contenedor Docker activo

Cuando usamos la opción -v de docker run, se hace un “bind mount” de la ruta indicada, con lo cual, de los sistemas de ficheros que estén montados por debajo de esa ruta, solo aparecerán dentro del contenedor los que estuvieran montados antes de ejecutar docker run.

A veces nos interesará incorporar dinámicamente sistemas de ficheros después de que se active el contenedor. Por ejemplo, para que sistemas de ficheros que se han montado a posteriori por debajo de la ruta “bind-mount-eada” aparezcan dentro del contenedor. A continuación resumo los pasos para conseguirlo en dos casos particulares: montar un volumen LVM y montar un recurso de red exportado por NFS (versión 4).

Instalar nsenter (incluido en las versiones recientes de util-linux) en el “docker host” (el servidor donde se crean los contenedores)

cd /usr/local/src/
wget https://www.kernel.org/pub/linux/utils/util-linux/v2.26/util-linux-2.26.2.tar.xz
tar xvfJ util-linux-2.26.2.tar.xz 
cd util-linux-2.26.2/
./configure
make -j 4 LDFLAGS=-all-static nsenter
cp nsenter /usr/local/sbin/

Averiguar el PID del contenedor en el cual queremos montar el sistema de ficheros

docker inspect --format "{{.State.Pid}}" CONTENEDOR
# PID

Obtener (en hexadecimal) los números del “dispositivo de bloque” correspondiente al sistema de ficheros

# nombre simbólico del volumen
ls -l /dev/mapper/NOMBRE_VG-NOMBRE_LV
# /dev/dm-XX
stat --format "0x%t 0x%T" /dev/dm-XX
# 0xab 0xcd

Replicar dentro del contenedor el fichero de dispositivo y el enlace

mknod --mode 0600 /dev/dm-XX b 0xab 0xcd
ln -s /dev/dm-XX  /dev/mapper/NOMBRE_VG-NOMBRE_LV
mkdir /mnt/tmp

Montar el sistema de ficheros con la ayuda de nsenter (ya que por defecto, desde dentro del contenedor “no tenemos permiso”, por razones de seguridad)

# Desde el docker host
nsenter --target PID --mount --uts --ipc --net --pid -- mount /dev/dm-XX /mnt/tmp

Si el sistema de ficheros que queremos montar es NFS, no hace falta la parte de replicar el fichero de dispositivo. Basta con que nfs-utils esté instalado en el contenedor.

# Desde el docker host
nsenter --target PID --mount --uts --ipc --net --pid -- mount -t nfs SERVIDOR_NFS:/RUTA/EXPORTADA  /RUTA/DESTINO/DENTRO/CONTENEDOR

Inspirado por el artículo sobre montaje dinámico de volúmenes en Docker de Jérôme Petazzoni

Combinar discos duros

Hay múltiples formas de combinar dos o más discos duros para disponer del espacio del conjunto en un sólo sistema de ficheros (en lugar de tenerlo fragmentado en varios)

La estrategia clásica es RAID, desde una concatenación secuencial (modo lineal) hasta un reparto que soporte el fallo de dos discos y aproveche todos para acelerar las operaciones de entrada salida (RAID 6). No obstante, con los discos actuales (de varios terabytes) los tiempos de reconstrucción son larguísimos, lo cual hace que la protección frente a fallo sea relativa.

Otra opción versátil es LVM, cuyas últimas versiones han integrado los diversos modos RAID: “a tiras” (stripping), espejo (mirroring o RAID1)… Y además permite combinar trozos (o discos) de distinto tamaño. Y hacer instantáneas (snapshots). Y usar transparentemente un disco de estado sólido (SSD) para acelerar las operaciones E/S del conjunto de discos.

Para el caso más simple, combinar dos discos, podemos optar por…

  • RAID0 (lineal o a tiras)
  • RAID 1
  • Un grupo de volúmenes LVM (VG)
  • una “mancomuna” ZFS (pool)
  • un sistema de ficheros btrfs multidispositivo
  • repartir “a mano” el espacio, montando el sistema de ficheros de uno de los discos dentro del sistema de ficheros del otro

NFS

NFS permite compartir directorios por red de forma sencilla en entorno Linux, aunque como todo tiene sus pegas (la principal, es sensible por defecto a cortes en la conexión cliente-servidor)

A continuación un pequeño ejemplo, en el que compartimos el directorio /nas/work/dir1 en server2 para que esté accesible en el directorio /mnt/server2/dir1 en client.

En NFS, configuramos lo que queremos hacer en ambos extremos. En el servidor, el fichero clave es /etc/exports:

# Una chuleta rápida de las opciones disponibles está en "man exports"
# Generalmente se puede omitir el fsid, pero si el sistema de ficheros donde se encuentra
# /nas/work/dir1 es XFS, <a href="https://www.mmacleod.ca/blog/2014/02/nfs-exports-and-xfss-inode64-mount-option/">mejor especificarlo</a> (a fin de evitar esotéricos problemas al montar
# o acceder al directorio...)
# rw -> lectura y escritura
# no_subtree_check -> "as a general guide, disable subtree_check"
# no_root_squash -> no "mapear" uid/gid 0 al uid/gid "anonymous"
/nas/work/dir1 client.xyz.com(rw,no_subtree_check,no_root_squash,fsid=1)

Ojo con utilizar fsid=0, ya que tiene un significado especial (“NFS root”)

Luego notificamos los cambios con exportfs:

# -r notifica y también hace limpieza (directorios que se han eliminado de /etc/exports)
# -f limpia completamente la tabla de exportacion en el kernel, y va añadiendo nuevas 
#    entradas segun los clientes hacen peticiones
exportfs -r

En el cliente, modificamos /etc/fstab:

# Una chuleta rápida de las opciones disponibles está en "man nfs"
# defaults -> opciones por defecto (se pueden comprobar concretamente con "mount" o "nfsstat -m"
#    Habitualmente son: relatime, vers=4, rsize=1048576, wsize=1048576, namlen=255, 
#    proto=tcp, port=0, sec=sys, minorversion=0, local_lock=none
# soft,retrans=N -> despues de N retransmisiones, se aborta la operación (hay una cierta
#    probabilidad de "corrupción de datos silenciosa")
# timeo=D -> esperar D decimas de segundo antes de reintentar mandar la petición (retransmisión)
# bg, retry=M -> permanecer intentando "montar" el recurso NFS en segundo plano (background)
#    durante M minutos
# intr -> permitir que señales interrumpan operaciones NFS (se ignora desde el kernel 2.6.25)
server2.xyz.com:/nas/work/dir1 /mnt/server2/dir1 nfs defaults,bg,retry=5,timeo=5,soft,retrans=5 0 0

Resolución de problemas

  • Añade la opción “-v” a mount
  • Verifica que el cliente puede ver los puertos del servidor (con nmap o similar)
  • showmount -e SERVER
  • rpcinfo -p SERVER
  • rpcdebug

Mas info: NFS Troubleshooting

Why file and directory operations are synchronous in NFS

Prioridades procesos Linux

A veces nos puede interesar priorizar los procesos corriendo en un Linux (por ejemplo, en un servidor concurrido en el que hay tareas de diversa importancia)

Para casos puntuales, lo más fácil es (impersonándose como la superusuaria Ruth) cambiar la prioridad indirectamente con (re)nice. Indirectamente porque los comandos nice y renice alteran el valor “niceness” (“majeza” :-P) del proceso. Cuánto más alto el valor, más majo es el proceso, o sea, más cede el paso a otros (menor prioridad para él mismo). El rango de valores para la “majeza” es de -20 a a 19.

En el caso de la prioridad de los procesos, funciona al revés: cuanto menor el valor, mayor la prioridad. Típicamente, una prioridad 0 sería la más alta, y 40 la menor. La prioridad por defecto sería 20. Pero ojo, todos estos valores son un poco relativos… Lo que los comandos de usuario (como top) muestran en realidad es el “raw nice value” para el espacio de usuario (que como hemos dicho, va de 0 a 40). Los valores “reales” de prioridades van definidos en el kernel (prio.h), con lo cual son susceptibles de cambio entre distribuciones y/o versiones del kernel (lo que a su vez podría afectar potencialmente a los rangos mencionados).

Para profundizar en estas sutilezas: “Understanding the Linux Kernel”, en O’Reilly; el paper “Understanding the Linux 2.6.8.1 CPU Scheduler” de Josh Aas (aunque ya tiene 10 años, sirve para los conceptos fundamentales); y/o el artículo “Understanding Linux Processes”

Si queremos hacer ajustes por defecto, podemos recurrir a PAM:

1) asegurarse de que se está cargando el módulo pam_limits para la aplicación que nos interesa. Por ejemplo, en /etc/pam.d/login debería haber una línea (sin comentar) tipo…

session    required   pam_limits.so

2) especificar la prioridad por defecto en /etc/security/limits.conf:

usuario_enchufado      -       priority        -10

En el ejemplo, se establece la niceness por defecto a -10, con lo que la prioridad por defecto para usuario_enchufado es 10 (más alta)

Podemos comprobar si los cambios han surgido efecto con ps o alguna variante de top, columna “priority”

Variables de entorno en bash

TLDR: coloca las definiciones en bashrc (/etc/bash.bashrc, o ~/.bashrc), antes del (posible) chequeo de interactividad.

Bash distingue entre entorno de inicio (login) y entorno interactivo.

En la mayoría de los casos, el entorno es interactivo (obviamente, ya que introducimos comandos “a mano”). Si ejecutamos un script bash (directamente, tipo “./mi_script”, o explicitando bash, tipo “bash -c mi_script” o “bash mi_script”), obviamente se considera “no interactivo”. Tampoco se considera interactivo la ejecución a través de la entrada estándar (por ejemplo, “echo ls | bash”). Si llamamos explícitamente a bash (por ejemplo, dentro de un terminal ejecutamos “bash”), sí se considera interactivo. En este sentido, a la primera ejecución de bash se le asigna el nivel 1 (“top level“), y a las sucesivas “sub-ejecuciones” se les va incrementando el nivel (con lo que dejan de ser “top-level”)

El entorno “de inicio” sólo lo “experimentamos” cuando entramos en el sistema (en local) o abrimos un terminal (en local). Estas sesiones se pueden identificar por el guión prefijo (“-bash” en lugar de “bash”).

Cuando ejecutamos un comando “directamente” (con su o ssh), el entorno no es ni de inicio ni interactivo.

Todo este trabalenguas tiene su importancia a la hora de definir variables de entorno, como PATH o LD_LIBRARY_PATH. Normalmente, se pueden colocar indistintamente en profile o en bashrc. Pero si necesitamos dichas variables en un entorno “no de inicio”, profile ya no nos vale.

Nos queda bashrc, que se procesa siempre… siempre que no haya una comprobación tipo…


# If not running interactively, don't do anything
[ -z "$PS1" ] && return

en cuyo caso, se ignora todo el código después del return.

Con lo cual, lo más seguro es lo que dice el TLDR (ver comienzo del artículo 😉 )

La única pega de este modelo es que, si vamos abriendo un entorno dentro de otro (ejecutando bash dentro de otro bash), las definiciones se pueden ir acumulando.

Un primer paso a la hora de resolver problemas de carga de configuraciones es mirar que tipo de shell se está usando en el caso de interés.

Si por ejemplo se necesita que ciertas variables estén disponibles al acceder por ssh, comprobamos el tipo de shell que se usa al entrar con ssh. Si empieza con “-“, ya sabemos que es una “shell de inicio”, con lo cual es mejor definir las variables en ficheros como ~/.profile.

Otra forma de averiguar el tipo de shell es imprimiendo la variable $- (opciones activas en la shell). Si la shell es interactiva, una de las letras sera la “i”.

La versión larga (resumida :-p )

En el fichero de código shell.c está la función run_startup_files() que es la que gestiona la carga de ficherros de configuración.

Resumiendo:

  • los intérpretes “no interactivos” no cargan ficheros de definiciones. Excepto que no esté en “modo POSIX” y no se llame “sh”, en cuyo caso se carga el fichero indicado en la variable BASH_ENV
  • cuando el intérprete es interactivo, o bash es llamado por su, la carga varía dependiendo de si es “login shell”. Cuando funciona como “login shell”, se cargan /etc/profile, ~/.profile, ~/.bash_profile y ~/.bash_login. En otro caso, se cargan /etc/bash.bashrc y ~/.bashrc
  • si bash funciona como una “top-level shell” ejecutada vía SSH, se carga ~/.bashrc.
  • si bash no está en “modo POSIX” y se llama con la opción –login (-l), se cargan las definiciones en /etc/profile, ~/.profile, ~/.bash_profile y ~/.bash_login
  • si bash está en “modo POSIX”, carga el fichero indicado en ENV

Visto de otro modo, ~/.bashrc se carga en los siguientes casos:

  1. top-level shell remota (ssh)
  2. shell interactiva no-de-inicio (su, ssh)

Curiosamente, en Debian 7.9 y posteriores (quizá antes de 7.9) no parece que se cargue automáticamente ~/.bashrc, con lo cual hay que cargarlo a mano desde ~/.profile

En builtins/evalfile.c:_evalfile encontramos las características que debe cumplir la ruta a cargar: que no sea un directorio a cargar (obvio), si no un fichero “normal” (“regular file”), que no sea demasiado grande, que no sea “binario” (por ejemplo, el fichero contiene más de 256 caracteres nulos), y que sea “correcto” sintacticamente.

Gestionar discos controladora LSI en sistema operativo

A veces resulta más práctico gestionar los discos conectados a una controladora RAID desde el sistema operativo. Si la BIOS no ofrece esa posibilidad, se puede buscar la manera de hacerlo en la propia controladora.

La interfaz grafica de LSI WebBIOS (Control-H) puede resultar limitada. Aunque no sea cómoda de usar, la linea de comandos “preboot CLI” (Control-Y) ofrece bastantes opciones. Los comandos son esencialmente los mismos de MegaCLI, con pequeñas diferencias sintácticas. La más importante es que cada guión es necesario (incluido el que va delante de cada comando)

# -a hace referencia al adaptador. Normalmente se puede usar el 0 (-a0)
# -page activa la paginación. En los siguientes ejemplos solo se incluye donde puede hacer falta
#   (salidas multipágina)
# ayuda
-h -a0 -page

# Comprobar si JBOD esta habilitado
-AdpGetProp -EnableJBOD -aALL

# Habilitar JBOD
-AdpSetProp -EnableJBOD -1 -aALL

# Listado de discos. Anotar los números de cabina (enclosure) y ranura (slot) de cada disco, para sucesivos comandos
-PDList -aALL -page

# Habilitar discos (si no se encuentran en estado "Unconfigured-Good"
-PDMakeGood -PhysDrv[Cabina:Ranura,...] -a0

# Configurar los discos como JBOD. Si JBOD no está soportado, aparece el mensaje "Failed to change PD state (...) Exit code 0x1"
-PDMakeJBOD -PhysDrv[Cabina:Ranura,...] -a0

# Crear un "RAID-0 de un solo disco"
-CfgLdAdd r0[Cabina:Ranura] -a0

# Comprobar que se ha creado correctamente
-CfgDsply -a0 -page

Estos comandos también se pueden ejecutar con la herramienta megacli.

Más info:

LSI MegaRAID en le-vert.net

MegaCli en Linux RAID Wiki

Depurar codigo Java JNI en Linux

Depurar una mezcla de código Java y C++ no es trivial, sobre todo porque aún no hay disponibles entornos (o plugins) estables que soporten esta posibilidad. Con lo cual hay que recurrir a la siguiente receta, que permite interactuar a la vez con los depuradores nativos de cada lenguaje (sean para consola como gdb, o gráficos como NetBeans)

Primero iniciar el programa en modo de depuración remota:

java -Xdebug -Xnoagent -Djava.compiler=none -Xrunjdwp:transport=dt_socket,server=y,suspend=y -Djava.library.path=$LD_LIBRARY_PATH -cp . -jar PROG.jar
Listening for transport dt_socket at address: 37112

Es importante definir java.library.path para que contenga el directorio donde se encuentra la biblioteca .so con el código nativo (en este caso, se le asigna el valor de la variable de entorno LD_LIBRARY_PATH).

Iniciar el depurador de Java y conectarse al puerto indicado por el comando anterior (en el ejemplo, 37112)

jdb -attach 37112

También se puede utilizar un depurador gráfico, por ejemplo el que viene con Eclipse. Para ello basta crear un perfil de depuración de tipo “Remote Java Application”. En Connection Properties usar localhost y como puerto el que nos devolvio el anterior comando java (siguiendo con el ejemplo, 37112)

Establecer el punto de parada en el código Java

stop at CLASE:NUM_LINEA
run

Una vez alcanzado el punto de parada en el código Java, iniciar el depurador de código nativo y vincularlo con el proceso java mediante su PID

gdb
attach PID
break JNI_FUNCTION

continue (retoma la ejecución del programa java)

Importante: para que el depurador C++ encuentre la función JNI, el programa Java debe tener ya cargada la biblioteca C++ (archivo .so). Si paramos la ejecución del programa Java demasiado pronto, cuando entremos en el gdb la biblioteca aún no se habrá cargado y por lo tanto al intentar el “break” se quejará de que no encuentra la función.

Estos tres comandos gdb también pueden ejecutarse dentro de ddd, lo cual nos permite depurar el código C++ con la comodidad de un entorno gráfico

Por último, de vuelta en jdb ejecutar run de nuevo (continua la ejecución en el depurador y se detiene en el breakpoint del código nativo definido en gdb)

Resolución de problemas de autenticación

ssh permite identificarse en un servidor remoto sin introducir una clave. Para ello basta con añadir nuestra clave pública en el fichero ~/.ssh/authorized_keys

ssh intenta ser precavido, con lo cual esta forma de identificación sólo funciona (por defecto) si sólo el usuario tiene posibilidad de escribir en su “home”. Con el sistema de permisos clásico de Unix/Linux, el usuario debe ser propietario de su home, y el permiso de escritura sólo puede estar habilitado para él (el típico patrón “755”)

Obviamente, el fichero de claves autorizadas tiene que ser correcto sintácticamente. A veces no es el caso, cuando uno “copia y pega” su clave y se cuela algún imperceptible salto de línea o espacio.

Además, la configuración del demonio SSH debe permitir el acceso con clave pública a ese usuario en particular. A veces no es el caso, bien porque el usuario es root y en la configuración se especifica “PermitRootLogin no”, o bien porque se declara “RSAAuthentication no” o “PubkeyAuthentication no”.

Para saber mas…

http://sial.org/howto/openssh/publickey-auth/problems/