Espacio de tecnologia, software libre y sus derivados. Una horda de monos entrenados escriben de vez en cuando por aqui algunas noticias, opiniones e incluso alguna que otra cosa fuera del tema. Maqueros, favor de abstenerse que no somos lo suficientemente guapos.
Me pidieron un programita hecho en C residente en memoria. Un demonio pues!…
Aqui les dejo el codigo base del daemon unix tradicional.
El daemon lo hice para un IBM AIX 5.3 sobre arquitectura power pc.
Y poco despues lo compile en linux, y no hubo nada de problema.. codigo 2000% porciento guapo y portable.
/**********************************
* UNIX Daemon Server Programming *
* Written by Edwin Plauchu *
* mailto:pianodaemon@gmail.com *
**********************************/
#include stdio.h
#include stdlib.h
#include fcntl.h
#include signal.h
#include unistd.h
#include string.h
#define RUNNING_DIR "/tmp"
#define LOCK_FILE "cacherd.lock"
#define LOG_FILE "cacherd.log"
void log_message(filename,message)
char *filename;
char *message;
{
FILE *logfile;
logfile=fopen(filename,"a");
if(!logfile) return;
fprintf(logfile,"%sn",message);
fclose(logfile);
}
void signal_handler(sig)
int sig;
{
switch(sig) {
case SIGHUP:
log_message(LOG_FILE,"Senal de hangup cachada");
break;
case SIGTERM:
log_message(LOG_FILE,"Senal de Terminacion cachada");
exit(0);
break;
}
}
void daemonize(){
int i,lfp;
char str[10];
// Primero obtenemos el indentificador de Proceso
if( getppid() == 1 ) return;
// Ahora generamos un proceso hijo y obtenemos su PID
// mediante la variable i
i=fork();
// Comprobamos que el proceso hijo este lanzado de manera correcta
// Verificando los posibles ERRORES de lanzamiento
// En caso de existir un error de lanzamiento en el proceso hijo
// procedemos a la finalizacion del proceso padre
if (i<0) { exit(1); } // fork error, el proceso hijo no pudo ser creado
if (i>0) { exit(0); } /* Padre existe */
// Proceso hijo (Demonio) continua
setsid(); // Crea una sesión y define el ID de grupo del proceso
/* Cerrar todos los descriptores de archivo
OJO: Esto evita que el hijo use los mismos decriptores de fichero que el padre*/
for (i=getdtablesize();i>=0;–i) close(i);
i=open(”/dev/null”,O_RDWR); dup(i); dup(i); /* handle standart I/O */
umask(027); /* Establece los permisos que le seran dados a los nuevos archivos a crear */
chdir(RUNNING_DIR); /* Cambia el directorio de ejecucion */
/* Abre el archivo de bloqueo en modo lectura/escritura, pero
si el archivo no existiece, lo crea con el permiso 640 */
lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);
if (lfp<0) { exit(1); } /* No puede ser abierto */
if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* No puede ser bloqueado el fichero para este proceso*/
/* Primera instancia continua */
sprintf(str,"%dn",getpid());
// Escribimos el PID al fichero de bloqueo
write(lfp,str,strlen(str));
signal(SIGCHLD,SIG_IGN); /* Ignora hijo */
signal(SIGTSTP,SIG_IGN); /* Ignora Senales tty */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGHUP,signal_handler); /* Cacha Senal hangup (kill -1 PID)*/
signal(SIGTERM,signal_handler); /* Cacha Senal de Terminacion (kill -15 PID)*/
}
int main(){ daemonize(); while(1) sleep(1); }
May 20, 2009 a las 3:28 pm por Edwin Plauchu · Archivado en Solaris
El kernel de solaris es multihilos,esto significa
que los servicios del kernel y tareas son ejecutados como hilos del kernel
El Hilo de Kernel es la unidad principal de ejecucion administrada por
el kernel de Solaris. El Hilo de Kernel tienen un estado de ejecucion
y contexto que inclulle una prioridad global y una clase de Planificacion de Tarea;
Los Hilos de kernel son las unidades fundamentales a ser administradas, ejecutadas
e intercambiadas de contexto sobre y fuera de los procesadores.
Este mismo modelo a los procesos de nivel de usuario.
El proceso de usuario es un contenedor que define bastante de el contexto
de ejecucion para sus hilos. Los hilos permiten multiples flujos de ejecucion
dentro de un solo entorno de memoria virtual.
Los siguientes objetos forman la implementacion y el modelo de hilos sobre el kernel de Solaris.
* Hilos de Kernel(Kernel threads): Es el objeto que se obtiene planificacion y ejecucion sobre un procesador. * Hilos de Usuario(User threads): El el hilo a nivel de usuario, mantenido por un proceso de usuario. * Proceso: Forma ejecutable de un programa; El entorno de ejecucion para un programa de usuario. * Proceso de peso ligero (Lightweight process (LWP)): El contexto de ejecucion visible del kernel, para un hilo de usuario.
Solaris ejecuta hilos de kernel para tareas relacionadas al kernel, tal como el manejo de interrupciones, administracion de paginas de memoria, drivers para dispositivos, etc.
Para la ejecucion de un proceso de usuario, los hilos de kernel tienen un LWP correspondiente LWP;
los hilos de kernel son planificados para ejecucion a favor de los procesos de usuario.
Dentro del kernel, multiples hilos de ejecucion comparten el entorno del kernel,
primariamente el spacio de direcciones del kernel.
Los procesos tambien contienen uno o mas hilos,los cuales comparten el entorno de memoria virtual
de los procesos, como tambien lo hacen otros componentes del contexto de proceso.
El LWP y su correspondiente hilo de kernel definen el entorno virtual de ejecuciont para un hilo dentro de un proceso de usuario. Cada hilo en un proceso de usuario es enlazado a un LWP
, y cada LWP tiene un hilo de kernel. El LWP permite a cada hilo dentro de un proceso, invocar llamadas al sistema
independientemente de otros hilos dentro del mismo proceso.
Cada vez que una llamada al sistema es realizada por un hilo,
sus registros son puestos sobre un stack dentro del LWP.
Una vez que la llamadas al sistema retornaron sus respuestas, estan ya estaran disponibles para LWP.
La siguiente figura muestra lo anteriormente expuesto:
Vamos a crear un buscador que busque en una tabla de nuestra base de datos y que según el número de palabras buscadas utilice LIKE o el Full Text Search de MySQL.
Que és Full Text Search?
El Full Text Search utiliza los índices de la tabla para hacer las búsquedas y hace las comparaciones de la misma forma que se hacen en los grandes buscadores y no como una comparación sencilla y costosa en tiempo como la utilizada por el like.
El resultado que devuelve es ordenado por similitud a las palabras o cadena buscada, esto se puede hacer ya que cuando va encontrando los resultados el mismo le asigna un indice de similitud a lo buscado, con lo que podemos saber lo exacto que es el resultado.
Para crear el índice en la tabla a buscar haremos:
ALTER TABLE noticias ADD FULLTEXT(titulo, texto);
Suponiendo que la tabla se llama noticias y los campos que queremos buscar són titulo y texto. Debemos tener en cuenta que los campos del índice solo pueden ser Char, Varchar o TEXT.
Nota: Los índices hacen que las tablas ocupen más espacio en disco peró agilizan mucho las búsquedas.
MATCH … AGAINST
Para buscar en la tabla utilizando el índice, haremos:
SELECT * FROM el índice WHERE MATCH(titulo, texto)
AGAINST ('palabras_a_buscar')
Si queremos saber noticias de similitud del resultado podemos hacer:
SELECT * FROM noticias WHERE MATCH(titulo, texto)
AGAINST ('palabras_a_buscar') AS similitud
Donde similitud sera el valor de aproximación a la busqueda.
Problemas del MATCH … AGAINST
El problema principal es que ens busquedas de una sola palabra acostumbra a fallar, ya que tiene un límite dado por el MySQL de busqueda de palabras mayores o iguales a 4 carácteres, por lo que si buscasemos por ejemplo PHP no tendriamos resultado. Lo que haremos es mirar si la cadena que nos llega es de una sola palabra o de más de una, en caso de ser una haremos la búsqueda usando LIKE y si es más de una usaremos MATCH … AGAINST Buscador con paginación.
//Conectar con la base de datos,
//también podemos poner el ADODB
//Yo utilizo conexiones con código directamente aquí
include ("conexion_bd.php");
if ($p_busca!='')
{ if (!$num) $num=0;
//Separamos las palabras usando cada espacio como separador
//Hacemos la separación de la cadena a buscar
$cadena_buscada=explode(" ",$p_busca);
if (count($cadena_buscada)==1)
{
//Si solo hay una palabra usamos LIKE
$sql=" SELECT SQL_CALC_FOUND_ROWS titulo, texto
FROM noticiasLIKE '%".$p_busca."%' OR texto LIKE '%".$p_busca."%'
WHERE titulo
LIMIT ".$num.",10";
}
elseif (count($cadena_buscada)>1)
{
//Si hay más de una palabra usaremos MATCH AGAINST
$sql=" SELECT SQL_CALC_FOUND_ROWS titulo, texto, MATCH (titulo, texto)
AGAINST MATCH (titulo,AS Score FROM noticias
('".$p_busca."') texto) AGAINST ('".$p_busca."')
WHERE BY Score DESC LIMIT ".$num.",10";
ORDER
}
$rs = $db->Execute($sql);
if (!$rs) echo $conn->ErrorMsg();
else if ($rs->fields["id"])
{ while (!$rs->EOF)
{ echo $rs->fields["titulo"].'‘.$rs->fields[”texto”];
} $rs->MoveNext();
}
else
echo ‘No se han encontrado resultados correspondientes a su búsqueda.’;
//Paginación
$rs_cont=$db->Execute (”select found_rows() as total_filas”);
if ($rs_cont->fields[”total_filas”]>10)
{ for ($i=0; $i<$rs_cont->fields[”total_filas”] && $i<50; $i=$i+10)
{ $a++;
echo '[’.$a.’] ’;
} }
}
December 28, 2007 a las 2:42 pm por Edwin Plauchu · Archivado en FreeBSD, Linux, Solaris
Los siguientes criterios de configuracion, los he aplicado a un servidor de 8 cores y 8 gb en RAM, y la cosa funciona de maravilla.
Sobre el MYSQL que corre en este servidor hay tablas tanto innodb como myisam. incluyo parametros para las dos engines.
[mysqld]
innodb_log_buffer_size=8M
#Explicacion: medida del buffer que innodb usara para su archivo de log.
#Consecuencia:Un buffer de log grande, permite a transacciones extensas ejecutarce, sin necesidad de acceso a disco antes de que la
# transaccion se confirme.
#Criterio de calculo: 1MB por cada GB de RAM.
innodb_buffer_pool_size=4294967296
#Explicacion: Empleado para almacenamiento intermedio de los datos e indices de sus tablas
#Consecuencia: Mientras mas grande sea este valor menos operaciones de IO disco seran necesarias para acceder a los datos de las tablas.
#Criterio de calculo: En un servidor de base de datos dedicado se puede asignar hasta el 80% de la memoria RAM. No dedicados Menos del 50% de RAM.
innodb_buffer_mem_pool_size=16M
#Explicacion: almacena info del diccionario de datos y estructuras internas, el valor por defecto es de 1MB
#Consecuencia: Evita que se haga paginacion a disco cuando, se acaba la memoria de este pool.
#Criterio de calculo: Entre mas tablas se tengan en la aplicacion, mayor debera ser el tamaño de este buffer,.
join_buffer_size=16777216
#Explicacion: buffer que se usa para joins que no usan índices (full joins)
#Consecuencia: obtencion de un full join más rápido ( cuando se añaden índices no es posible.)
#Criterio de calculo:2097152 bytes por cada Gigabyte de RAM.
skip-bdb
skip-ndbcluster
#Explicacion: Deshabilita el soporte para base de datos bdb y ndbcluster
#Consecuencia: Ahorro en la memoria asignada por sistema operativo al proceso mysqld
innodb_data_file_path=/dev/hdc1:250MBraw;/dev/hdc2:250MBraw
#Explicacion: Utilizar dispositivos crudos como Datafiles
#Consecuencia: Aumento en velocidad relacionada a operaciones de IO sobre disco.
query_cache_size=134217728
#Explicacion: Almacena el texto de una consulta SELECT junto con el resultado que se le envió al cliente.
#Consecuencia: Si se recibe una consulta idéntica posteriormente, el servidor devuelve el resultado de la
# caché de consultas en lugar de parsear y ejecutar la consulta de nuevo.
#Criterio de calculo:16777216 bytes por cada Gigabyte de RAM.
query_cache_limit=1M
#Criterio de calculo: consultas menores a 1MB no merecen ser cacheadas.
query_cache_type=1
#Consecuencia: Permite el cacheo excepto para aquellos comandos que empiecen con SELECT SQL_NO_CACHE
key_buffer_size=100663296
#Explicacion: Cachea los bloques de índices para tablas MyISAM. Cada vez que una búsqueda usa un índice,
# MySQL mirará antes de nada a ver si el índice relevante está o no en memoria.
#Consecuencia: Incrementando el valor se obtiene un mejor tratamiento de índices y por consecuencia, mejor rendimiento.
#Criterio de calculo:12582912 bytes por cada Gigabyte de RAM. Pero si solo se utilizan tablas MyISAM utilice 5% a 50% de la RAM.
sort_buffer=67108864
#Explicacion: Búffer de ordenación se usa para responder a búsquedas que involucren el ordenamiento de los datos -aquellas
# con una sentencia ORDER BY en ellas. Además, el búffer de ordenaciónse usa para las búsquedas que involucren
# agrupar datos -aquellas con una sentencia GROUP BY.
#Consecuencia: Reduce dramáticamente la cantidad de tiempo que se usa para ordenar grandes grupos de resultados
#Criterio de calculo: 8388608 bytes por cada Gigabyte de RAM.
read_buffer_size=8M
#Explicacion: Cada thread que realiza un escaneo secuencial reserva un buffer de su tamaño (en bytes) para cada tabla que escanea.
# Si realiza muchos escaneos secuenciales, puede incrementar este valor.
#Consecuencia: Mejora el rendimiento en los escaneos secuenciales.
#Criterio de calculo: 1MB por cada Gigabyte de RAM.
open_files_limit=4096
#Explicacion: limite de archivos abiertos por mysql
#Consecuencia: Ciertas operaciones requeriran mas de 1024 descriptores de archivos abiertos en mysqld, sobre todo aplicaciones web.
#Criterio de calculo: 1024 es el predeterminado, aumente este valor si observa errores referentes a esto en el log de errores de mysql.
# No aumente este valor mas alla de 4kb.
[mysqldump]
quick
Si tienen algo que agregar a esta configuracion, u algun otro criterio, lo anexare a este articulo a la brevedad.
Feliz año nuevo 2007
lsof (ls Open Files) o listado de archivos abiertos, es una gran aplicación pero bastante desconocida y que nos puede sacar de muchas dudas o apuros. lsof es una herramienta muy completa, por lo que en éste articulo solo se muestra la información que más vamos a necesitar.
NOTA: Si se quiere saber más sobre el uso de lsof ejecutad “man lsof “.
Utilidad de lsof.
Como he dicho antes, lsof muestra los archivos y procesos abiertos en el moment o del chequeo, por lo que nos será de utilidad para llevar un seguimiento de seguridad o de procesos bloqueados.
Desmontando un CD rebelde.
# umount /cdrom
umount: /cdrom: device is busy
Vaya, ¡¿por qué no se desmonta y me dice que el dispositivo está ocupado?! No se ha desmontado porque algun proceso esta haciendo uso del CDROM y hasta que no lo libere no podremos desmontarlo, el problema es que desconocemos que aplicacion se encuentra usando dicho CDROM, mediante lsof podremos conocerlo.
# lsof +D /cdrom
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
konqueror 621 zx80 cwd DIR 3,64 2048 57344 /cdrom
lsof nos dice que el proceso konqueror está usando el directorio /cdrom con el usuario zx80. La solución es sencilla entoces, basta con cerrar konqueror y problema resuelto. Para los que usamos mucho la consola y llegamos a tener unas cuantas sesiones abiertas pasa que en vez de konqueror puede salir bash. Esto es debido a que alguna de las consolas está dentro del directorio activo del cd-rom, por lo que bastaría salirse del directorio de trabajo del CD o cerrar ese bash.
# kill 621
Ya podemos desmontar.
Quien está detrás de una conexión ?
Esta vez usamos la herramienta netstat. Para quien no conozca esta herramienta decir que es un monitor de red. Nos dirá qué conexiones activas tenemos y mucha inform ación sobre ellas. Vamos a ver qué conexiones tenemos activas:
# netstat - n
Active Internet connections (only servers)
Proto Recv- Q Send - Q Local Address Foreign Address
tcp 0 0 *:printer *:* LISTEN
tcp 0 0 localhost:www *:* LISTEN
tcp 0 0 *:6000 *:* LISTEN
tcp 0 0 *:smtp *:* LISTEN
Nos muestra información sobre algunos puertos en espera (Listen) pero desconocemos qué aplicación está detrás. Me llama la atención el puerto TCP 6000, así que voy a ver quien está detrás:
# lsoft - i :6000
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
X 279 root 3u Ipv4 349 TCP *:3000 (LISTEN)
Vemos que la aplicacion X es la culpable de que el puerto 6000 esté abierto y a la espera.
Qué procesos están usando un directorio.
Una de las utilidades que más se usan es averiguar qué aplicaciones están trabajando en un directorio concreto. Se usa esta opción sobre todo para vigilar el uso de troyanos o espias. SI quisiera saber qué procesos están usando mi directorio pondría lo siguiente:
pianodaemon@pianodaemon-laptop:~$ lsof +D /home/pianodaemon/
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
x-session 5962 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
compiz 6013 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
gnome-pan 6015 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
nautilus 6017 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
emerald 6127 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
compiz.re 6128 pianodaemon cwd DIR 8,1 4096 6684674 /home/pianodaemon/
................ ...
Otros usos.
Estos son otros usos de la herramienta lsof, que aunque son algo menos usados nos pueden sacar de algun apuro o duda.
# lsof - g n: Donde n es un ID de grupo.
Esto muestra los archivos abiertos por un grupo que queramos. Si quisieramos ver los archivos de varios grupos a la vez, los separariamos por comas:
# lsof - g wheel,users
# lsof - u n: Donde n es un ID de usuario, lo que nos mostrará los archivos abiertos por ese usuario. Al igual que con los grupos, se pueden especificar varios usuarios de una vez.
# lsof - l: Para no convertir el ID a nombre de usuario, útil en casos de logeos corruptos o sistemas lentos.
# lsof - N: Nos muestra los archivos NFS abiertos.
Como muchos ya saben, muchas cosas se manejan en Unix, y en consecuencia en Linux, como si fueran archivos, se abren, se cierran, se escribe en ellos, etc. Este pequeño artículo hace referencia a las marcas de tiempo que ponen los Unix en dichos archivos. Al menos los que estan basados en inodes.
Viendo las marcas de tiempos
Para el principiante el comando ls es su primera opción pero si entra en problemas, como yo lo hice, puede que se frustre con dicho comando. Ejemplo:
¿ En este caso qué marca de tiempo estamos viendo ?
Las tres marcas
Unix pone tres marcas de tiempo a un archivo:
Access
Modify
Change
stat el comando
stat es parte del paquete coreutils de GNU. Por favor, instalatelo si esta disponible para tu plataforma, hasta donde se, Linux, AIX, Solaris, y otros sabores de Unix, Esto te va a ahorrar muchos dolores de cabeza.
Cuando se crea por primera vez un archivo, por ejemplo con el comando touch, las tres marcas tienen el mismo valor. Miremos ahora la salida de stat del mismo archivo ejemplo:
¡Esto si es información completa ! Vemos reportado, el nombre, el tamaño, los bloques, el tipo de archivo (regular), información física de donde se encuentra (dispositivo/inode), los permisos estandar, los dueños del archivo y las tres marcas de tiempo Unix.
Opciones interesantes de formato de salida del comando stat:
%X Time of last access as seconds since Unix Epoch
%x Time of last access
%Y Time of last modification as seconds since Unix Epoch
%y Time of last modification
%Z Time of last change as seconds since Unix Epoch
%z Time of last change
Las opciones en mayúscula nos imprimen la marca de tiempo transcurrido desde la Epoca Unix, y las opciones en minúscula imprimen la marca de tiempo legible para el humano.
Ejemplo:
root@pianodaemon-laptop:/home/pianodaemon# stat --format=%X proto.sh
1194650864
root@pianodaemon-laptop:/home/pianodaemon# stat --format=%x proto.sh
2007-11-09 17:27:44.000000000 -0600
Ambos “números” son equivalentes m¡s el primero es un número absoluto, el segundo es interpretado ya que muestra la configuración de la zona horaria (-0600). Mi configuración de hora/fecha es zona America/Mexico y uso UTC.
Marca de Tiempo
Las marcas de tiempo se almacenan en el inode del archivo correspondiente con, hasta donde he confirmado, 32 bits de codificacion. Estos enteros son con signo, los negativos representan fechas en el pasado de la época Unix, y los positivos, fechas futuras desde la época Unix. La época Unix es la hora/fecha 00:00:00 UTC del 1ero de Enero de 1970.
Algunos datos para desarrolladores Python
En lo personal prefiero el desarrollar scripts sobre el interprete Python a bash. Asi que uso stat sobre el mismo:
import os, glob
from stat import *
for folder in glob.glob( base_path ):
for file in glob.glob( folder + '/*.mp3' ):
print file
# retrieves the stats for the current file
# return the last-modified-date
last_mod_date = os.stat( file )[ST_MTIME]
print last_mod_date