Copyright © 2005-2019 LinuxTotal.com.mx
Se concede permiso para copiar, distribuir y/o modificar este documento siempre y cuando se cite al autor y la fuente de linuxtotal.com.mx y según los términos de la GNU Free Documentation License, Versión 1.2 o cualquiera posterior publicada por la Free Software Foundation.
Uno de mis clientes tiene múltiples aplicaciones basadas en VisualBasic 6 y como base de datos Access, que se ejecutan directamente en un servidor Linux con Samba a través de shares (recursos o directorios compartidos en el servidor) y en los clientes que son WindowsXP, unidades de red que apuntan a los shares de samba. El problema está en que Access bloquea la base de datos y cuando necesita hacer una actualización, necesita buscar cuál de los 100 (mas o menos) usuarios es que esta utilizando la aplicación. Asi que aunque sea un solo usuario el que este usando el programa, necesita (o necesitaba) tomar el teléfono y marcar varias extensiones hasta encontrar al "culpable" pedirle que se saliera de la aplicación, subir la actualización al servidor.
Claro, la mejor solución en este caso es que cambié de Microsoft Access a MySQL. Implica cambiar la conexión a la base de datos en VisualBasic6, quizás ajustar el método de conexión (de DAO a ADO) para un mejor rendimiento, etc. pero el resultado serán aplicaciones más sólidas y estables y sin el problema del bloqueo de la base de datos cuando se requiere actualizarla o compactarla o repararla (ya conocen Access).
Pero mientras hace lo anterior, una combinación de programas de Linux pueden ayudarte a determinar quien en la red esta usando recursos compartidos en cualquier momento, permitiéndote decirle al o a los usuarios que se salgan del sistema (de la unidad de red) mientras actualizas el sistema.
Entonces, hice un script para resolver el problema. Usando una combinación de lsof
, netstat
, gawk
, grep
, uniq
y otras utilerías del bash shell. Todos los ejecutables de las aplicaciones están almacenados en /usr/apps y en subcarpetas nombradas 'nomina', 'contabilidad', 'ventas', etc. Asumiendo por ejemplo que se requiere saber todas las direcciones IP de los usuarios que están usando el sistema de nómina, se usa lsof
(list open files) que lista los archivos abiertos.
#> lsof | grep /usr/apps/nomina smbd 16258 systems cwd DIR 8,5 4096 2191586 /usr/apps/nomina smbd 16258 systems 27rR REG 8,5 2449408 2191760 /usr/apps/nomina/nomina.exe smbd 16258 systems 28u REG 8,5 37883904 1684790 /usr/apps/nomina/dbnomina.mdb smbd 16258 systems 29uw REG 8,5 256 1684290 /usr/apps/nomina/dbnomina.ldb smbd 19237 systems cwd DIR 8,5 4096 2191586 /usr/apps/nomina smbd 19237 systems 25rR REG 8,5 2449408 2191760 /usr/apps/nomina/nomina.exe smbd 19237 systems 27u REG 8,5 37883904 1684790 /usr/apps/nomina/dbnomina.mdb smbd 19237 systems 28uw REG 8,5 256 1684290 /usr/apps/nomina/dbnomina.ldb smbd 19237 systems 29rW REG 8,5 45056 1684863 /usr/apps/nomina/report1.rpt
lsof
listaría varias decenas de líneas de archivos abiertos, asi que con grep
filtramos solo aquellas líneas que tienen el patrón buscado '/usr/apps/nomina'. En este caso, la salida muestra que Samba (smbd) tiene varios archivos abiertos, y que son los procesos PID 16258 y 19237, aqui ya se puede apreciar que dos usuarios son los que están usando el archivo 'nomina.exe'. También observamos que la última línea muestra que el archivo 'reporte1.rpt' esta siendo usado, esta es una extensión típica de Crystal reports, asi que se deduce que también está aplicación esta tmbién ocupada. Sin embargo, el listado previo aun no nos muestra que usuarios los están utilizando. Asi que extraemos solo lo necesario de lo anterior que son los números de proceso (PID).
#> lsof | grep /usr/apps/payroll | gawk '{ print $2 }' 16258 16258 16258 16258 19237 19237 19237 19237 19237
Con gawk
, es posible indicar que solo se requiere el segundo campo. Pero no necesitamos todas esas repeticiones, asi que ahora concateno el comando uniq
, el cual permite remover líneas duplicadas de una lista ordenada:
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq 16258 19237
Ahora, se envía el resultado a un archivo temporal:
#> lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp
A continuación, hay que relacionar esos números de procesos PIDs con un socket de red, usando el comando netstat
con la opción -p. netstat
mostrará el PID y el nombre del programa al que el socket pertenece, por ejemplo:
#> netstat -p | grep 16258 tcp 0 0 192.168.100.250:netbios-ssn 192.168.100.32:1028
La cuarta columna (192.168.100.250:netbios-ssn) es el servidor donde se alojan las palicaciones y la quinta columna (192.168.0.32:1028) es la dirección IP y el número de puerto del equipo cliente, el dato que se esta buscando!!.
Asi que ahora ponemos todo junto en un script que leera los PIDs del archivo 'tmp' temporal.
lsof | grep /usr/apps/payroll | gawk '{ print $2 }' | uniq > tmp echo "EQUIPOS USANDO LA APLICACIÓN:" while read renglon ; do netstat -p | grep $renglon | gawk '{ print $5 }' | cut -d":" -f1 done < tmp
La línea netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1
primero ejecuta netstat
después llama a grep
con la variable $renglon, que viene de cada renglón del archivo 'tmp'. Extrae la quinta columna con gawk
, entonces con cut
y el delimitador ':' indicado por -d, extrae el primer campo que es efectivamente la dirección IP.
Se le da al sript un nombre (script.sh por ejemplo), se cambian sus permisos a digamos chmod 700 script.sh
para hacerlo ejecutable. Y cuando lo ejecutes el resultado será algo como lo siguiente:
./script.sh EQUIPOS USANDO LA APLICACIÓN: 192.168.100.32 192.168.100.78
Bien, ya está funcionando, ya podemos ver quien esta conectado en este momento usando la nómina, pero sería mejor se pudieramos saber a quien pertenece la IP, asi que basta con que modifiquemos el archivo /etc/hosts donde añadiremos una línea por cada IP de nuestra red, seguido del nombre del usuario, algo como lo siguiente:
127.0.0.1 localhost 192.168.100.32 Lindsay_Hayek 192.168.100.78 Salma_Lohan 192.168.100.145 Tom_Norton 192.168.100.193 Edward_CruiseLa línea de 'localhost' no debes eliminarla. Y se añade un grep
adicional para que el resultado de la línea netstat
sea el argumento a buscar dentro de /etc/hosts:
grep - w `netstat -p | grep $row | gawk '{ print $5 }' | cut -d":" -f1` /etc/hosts
Nótese que la línea original está entre comillas graves ` ` o también llamadas backticks, el argumento -w sirve para buscar concordancias exactas, asi '192.168.0.13' solo buscará esa IP y no '192.168.0.132'.
Sin embargo, si el script encuentra una IP que por no se haya añadido a /etc/hosts, mandará un error en vez de simplemente imprimir la dirección IP. Para resolver este pequeño problema, lo resulevo con una sentencia if
. Si la instrucción previa es correcta (se sabe que es correcta cuando regresa un 0 a través de la variable '$?'), entonces el script imprime IP-usuario y continua al siguiente renglón dentro del archivo 'tmp', y cualquier cosa aparte de 0 indicará que la dirección IP no se encontró dentro de /etc/hosts, asi que solo se imprime la IP. Para saber quien es el usuario, pues tendremos que consultar con el administrador de la red o alguna lista de relación IP-usuario. EL script entonces queda algo como lo siguiente:
lsof | grep /usr/apps/nomina | gawk '{ print $2 }' | uniq > tmp echo "EQUIPOS USANDO LA APLICACIÓN:" while read renglon ; do grep -w `netstat -p | grep $renglon | gawk '{ print $5 }' | cut -d":" -f1` /etc/hosts if [ $? -ne 0 ]; then netstat -p | grep $renglon | gawk '{ print $5 }' | cut -d":" -f1 end if done < tmp
En el if
se evalua la expresión que quiere decir si '$?' es diferente '-ne' de 0 entonces solo imprime la IP.
Si se ejecuta de nuevo el script, el resultado podría ser lo siguiente:
#> ./script.sh EQUIPOS USANDO LA APLICACIÓN: 192.168.100.32 Lindsay_Hayek 192.168.100.78 Salma_Lohan 192.168.100.90
Por último, podemos mejorar el script aun más. Ya que en la primera línea donde dice '/usr/apps/nomina' tenemos que estar cambiando 'nomina' a algo más cada vez que deseamos buscar por otra aplicación, entonces podemos sustituirla por lo siguiente:
lsof | grep /usr/apps/$1 | gawk '{ print $2 }' | uniq > tmp echo "EQUIPOS USANDO LA APLICACIÓN $1:"
Donde '$1' es un argumento de script.sh que se indica en la línea de comandos, y al ejecutarlo entonces sería de la siguiente manera:
#> ./script.sh contabilidad EQUIPOS USANDO LA APLICACION contabilidad: 192.168.100.145 Tom_Norton 192.168.100.178 192.168.100.193 Edward_Cruise
Hay ciertamente otras maneras de lograr lo anterior, espero que este ejemplo te sirva para entender mejor los shell scripts en Linux.
Si encuentras útil la información que proveé LinuxTotal, considera realizar un donativo que estimule a seguir proporcionando contenido de calidad y utilidad. Gracias.
Dona a través de paypal::
O a través de bitcoins:
El comando find de Linux es extremadamente potente. No hay nada mejor para hacer todo tipo de búsquedas de archivos y carpetas qu....
El siguiente script te presenta la manera de colocar un reloj (hora y fecha) en la parte superior derecha de una terminal de texto....
rsync es probablemente la herramienta de copiado y sincronización de archivos más potente que existe en el mundo de Linux/Unix. ....
En SQL, 'Alter' es un comando de la categoría DDL (Data Definition Language) y como su nombre lo indica sirve para alterar objeto....
Si se tiene un servidor ssh al que seguramente se conectan clientes desde otros equipos Linux o Windows con clientes de ssh como p....
Aqui, traté de enviar un archivo ejecutable (notepad.exe) a través de gmail, y sus mecanismos de seguridad me lo impidieron. Gma....
Una tarea administrativa algo común, es eventualmente tener que añadir un nuevo disco duro (IDE) al o a los que ya se tienen, de....
En el artículo de LinuxTotal.com.mx sobre permisos se explica lo que es un archivo con permisos SUID o SGID, pueden ser potencial....
El directorio /proc es una bestia extraña. Realmente no existe, sin embargo puedes explorarlo. Sus archivos de tamaño 0 no son n....
awk o la versión GNU gawk es más que un simple comando de procesamiento de patrones, es todo un lenguaje de análisis semántico....