1. Servicios
y
demonios
Código residente de ejecución con
frecuencia programada para
procesamiento de eventos
2. Programas residentes
• Procesos que se arrancan y cuando finalizan
dejan parte de su código instalado en
memoria.
• El código residente queda protegido por el
sistema de administración de memoria del
S.O.
• El código resiente no se ejecuta por
intervención directa del usuario.
3. Programas residentes
• El código residente se ejecuta mediante
señales de software o interrupciones de
hardware.
• Los programas AGENTES son rutinas
residentes, diseñadas para Windows, tienen
una interfaz GUI oculta y se registran en la
barra de tareas del sistema.
4. Servicios
• Programas residentes, sin interfaz gráfica, que son
iniciados al arrancar el sistema.
• No requieren que un usuario se registre para entrar
en ejecución, siempre están activos.
• Pueden ser configurados para arrancar en forma
automática, manual o para ser deshabilitados.
5. Interfaz con el “Service Control
Manager”
• Se administran mediante la aplicación de
servicios (“services”) dentro del Panel de
Control/Herramienta.
6. Servicios
• Los servicios pueden añadirse dinámicamente.
• Los estados de un proceso son:
– Habilitado
– Deshabilitado
– Iniciado
– Iniciando
– Detenido
– Deteniéndose
• Su inicio puede ser:
– Manual
– Automático
7. Servicios
• Los servicios pueden activarse o desactivarse
según se requiera, sin necesidad de reinicializar el
sistema.
8. Para instalar un proceso se requiere ...
Programa instalador.
Da de alta el programa del proceso dentro de la
base de servicios (procesos) de Windows.
Programa del proceso.
Contiene el código funcional del servicio
(proceso).
10. Eventos que puede
recibir/enviar un servicio
• SERVICE_STOPPED
• SERVICE_START_PENDING
• SERVICE_STOP_PENDING
• SERVICE_RUNNING
• SERVICE_CONTINUE_PENDING
• SERVICE_PAUSE_PENDING
• SERVICE_PAUSED
• SERVICE_ACCEPT_STOP
• SERVICE_ACCEPT_PAUSE_CONTINUE
• SERVICE_ACCEPT_SHUTDOWN
11. Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]="Srv_ProgAva";
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);
void main(void)
{
tabla.lpServiceName=nombreServicio;
tabla.lpServiceProc=&ServiceMain;
StartServiceCtrlDispatcher(&tabla);
}
Declaración de las rutinas que servirán para las
operaciones principales del servicio.
Estas hay que indicarlas ya que sus nombres no
son estándares de Windows, sino un capricho del
programador.
12. Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]=“Srv_ProgAva";
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);
void main(void)
{
tabla.lpServiceName=nombreServicio;
tabla.lpServiceProc=&ServiceMain;
StartServiceCtrlDispatcher(&tabla);
}
Declaración de la estructura de datos
SERVICE_TABLE_ENTRY.
Inicialización de la estructura.
13. Estructura SERVICE_TABLE_ENTRY
“The SERVICE_TABLE_ENTRY structure is used by the
StartServiceCtrlDispatcher function to specify the ServiceMain
function for a Win32 service that can run in the calling process.”
typedef struct _SERVICE_TABLE_ENTRY {
LPTSTR lpServiceName;
LPSERVICE_MAIN_FUNCTION lpServiceProc;
} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;
“Members
lpServiceName Pointer to a null-terminated string that names a
service that can run in this service process. This string is ignored if
the service is installed in the service control manager database as a
SERVICE_WIN32_OWN_PROCESS service type. For a
SERVICE_WIN32_SHARE_PROCESS service process, this string
names the service that uses the ServiceMain function pointed to by
the lpServiceProc member.”
14. Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]="Srv_ProgAva";
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);
void main(void)
{
tabla.lpServiceName=nombreServicio;
tabla.lpServiceProc=&ServiceMain;
StartServiceCtrlDispatcher(&tabla);
}
Declaración de las rutinas que servirán para las
operaciones principales del servicio.
Estas hay que indicarlas ya que sus nombres no
son estándares de Windows, sino un capricho del
programador.
15. Función StartServiceCtrlDispatcher
The StartServiceCtrlDispatcher function connects the main thread of a service process to the service
control manager, which causes the thread to be the service control dispatcher thread for the calling
process.
BOOL StartServiceCtrlDispatcher(
LPSERVICE_TABLE_ENTRY lpServiceStartTable // address of service
// table
);
Parameters
lpServiceStartTable
Pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service
that can execute in the calling process. The members of the last entry in the table must have NULL
values to designate the end of the table.
Return Values
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
Errors
The following error code can be set by the service control manager. Other error codes can be set by
the registry functions that are called by the service control manager.
Value Meaning
ERROR_INVALID_DATA The specified dispatch table contains entries that are not in the proper
format.
ERROR_SERVICE_ALREADY_RUNNING Windows NT 5.0 and later: The process has already
called StartServiceCtrlDispatcher. Each process can call StartServiceCtrlDispatcher only one time.
16. Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ...
// ESTAMOS INICIANDO
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
Inicialización de la estructura serviceStatus para
interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
preparar el arranque del servicio.
SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
17. Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ...
// ESTAMOS INICIANDO
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
Registrar la rutina que de ahora en adelante servirá
interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
para recibir mensajes del sistema operativo.
SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
18. Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ...
// ESTAMOS INICIANDO
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
Mandar la ServiceManager la indicación de que
interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
nuestro servicio ya está activo.
SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
19. Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ...
// ESTAMOS INICIANDO
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
Llamar a nuestra rutina de inicialización ... mmmh, aunque
esto debió haberse hecho antes del SetServiceStatus,
interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
no? ... ¿por qué?
SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
20. Rutina mainHandle
VOID WINAPI mainHandle(DWORD fdwControl)
{
switch(fdwControl) {
case SERVICE_CONTROL_STOP:
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_STOP_PENDING;
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
...
break;
case SERVICE_CONTROL_PAUSE:
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_PAUSE_PENDING;
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
...
break;
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING;
...
}
} El servicio debe tener capacidad para responder
a cada tipo de petición que pueda generar el
21. Rutina mainHandle
....
case SERVICE_CONTROL_CONTINUE:
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING;
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
SetServiceStatus(interfaz_al_SCM,&serviceStatus);
reactivarProceso();
serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState=SERVICE_RUNNING;
serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
|SERVICE_ACCEPT_STOP
|SERVICE_ACCEPT_PAUSE_CONTINUE
|SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode=NO_ERROR;
serviceStatus.dwServiceSpecificExitCode=0;
serviceStatus.dwCheckPoint=estado++;
serviceStatus.dwWaitHint=100;
SetServiceStatus(interfaz_al_SCM,serviceStatus);
break;
} Cada caso puede tener llamadas a diversas
...
rutinas, según corresponda para realizar
22. Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O.
char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla.
char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
23. Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O.
char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla.
char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
24. Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O.
char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla.
char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
25. Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
26. Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
27. Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";
SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio
ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;
void main(void) {
manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
resume=0;
for (i=0;i<20;i++) {
resume=i;
if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
SERVICE_STATE_ALL,&datos[0],sizeof(datos),
&bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
printf("(%d) Error!n",GetLastError());
else {
printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
}
}
28. Ejemplo del instalador de un servicio
if((nuevoServicio=CreateService(manejadorServicios,
nombreServicio,nombreDisplay,SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,pathServicio,
NULL,NULL,NULL,NULL,NULL))==NULL)
printf("(%d) Error al crear el servicio %sn",
GetLastError(),nombreServicio);
else
printf("Servicio %s creado!!!n",nombreServicio);
getchar();
} //main
29. ‘¡¡¡Demonios!!!’ … “Linux Daemons”
• Son procesos que se activan al iniciar la operación
del “kernel” y finalizan cuando se apaga el
sistema.
• No requieren interacción con el usuario, por lo
tanto son procesos que no tienen terminal de
control y por eso se dice que se ejecutan en
“background”.
• Debido a lo anterior, el flujo de salida y de errores
debe tratarse de manera particular.
30. Señales y demonios
• Los procesos tipo “daemon” siguen un protocolo
específico para interactuar con el “kernel” y con
las aplicaciones que los requieren.
• Las interfaces hacia un “daemon” pueden ser
(entre otros):
– Archivos.
– “Pipes”.
– “Sockets”.
– Señales.
• Su funcionamiento es similar al de un servicio en
Windows, pero tienen una codificación distinta.
31. Señales de demonios
• Las señales son eventos (interrupciones) de “software”.
• Son útiles para procesar eventos asincrónicos (teclado, red,
archivos, etc).
• La definición de señales es particular de la implementación
del sistema operativo, pero en el archivo <signal.h> se
pueden encontrar las definiciones estándares.
• Un programa define rutinas específicas para capturar
señales, en él establece sus reglas de procesamiento; para
esto se utiliza la directiva:
void (*signal(int signo, void (*func)(int)))(int);
32. Señales
• Al recibir una señal, un proceso puede hacer tres cosas:
– Ignorar la señal.
– Atrapar la señal y procesarla mediante su rutina de atención
(“handler”); aunque se debe saber que hay señales que no se puede
interceptar, tal como SIGKILL y SIGSTOP.
– Pasar el evento al sistema operativo para que se realice su
procesamiento de facto.
• Para enviar una señal a un proceso se pueden utilizar un par de rutinas:
int kill(pid_t pid, int signo);
int raise(int signo);
• Igualmente se puede enviar una señal desde una terminal utilizando el
comando kill y conociendo en número de proceso.
33. “Signal handler”
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static void signalHandler(int signo) { //El argumento es el número de la señal
if (signo == SIGUSR1)
printf("received SIGUSR1n");
else if (signo == SIGUSR2)
printf("received SIGUSR2n");
else if (signo == SIGINT)
printf("CTRL-C!!!n");
else if (signo == SIGQUIT) {
printf("Bye, bye.n");
exit(0);
} else if (signo == SIGKILL)
printf("It will be not so easy to get rid of me!!!n");
else
printf("received signal %dn", signo);
}
int main(void) {
34. Catálogo de señales
Señal Acción de facto Descripción
SIGABRT “Terminate+core” Esta señal se genera al invocar la rutina abort(…) {<stdlib.h>}
SIGALRM “Terminate” Es invocada cuando expira el tiempo establecido por la rutina
alarm(…) {<unistd.h>. También está relacionada con la rutina
setitimer(…).
SIGCHLD “Ignore” Se genera en el proceso padre cuando un proceso hijo termina o
se detiene.
SIGCONT “Continue/ignore” Esta señal es útil para reactivar un proceso que ha sido detenido
previamente
SIGHUP “Terminate” Esta señal se envía a un proceso en caso de detectarse que su
terminar controladora se ha desconectado o cerrado.
SIGINT “Terminate” Esta señal se genera al detectarse la pulsación de la combinación
de teclas <Control-C>.
SIGIO “Terminate/ignore” Se activa para indicar la detección de un evento asincrónico de E/
S.
SIGKILL “Terminate” Es una de las que no es interceptable, siempre útil para brindar
una forma segura para finalizar un proceso.
SIGPIPE “Terminate” Esta señal marca un error en el mecanismo de comunicación entre
procesos a través de “pipes”.
35. Catálogo de señales
Señal Acción de facto Descripción
SIGQUIT “Terminate+core” Es similar a SIGINT, pero adicionalmente genera un archivo de
depuración de errores (“core dump file”).
SIGSTOP “Stop process” No puede ser interceptada ni ignorada, es la forma correcta de
finalizar un proceso.
SIGTERM “Terminate” Esta señal es generada por el comando “kill” de facto, sin
parámetros adicionales.
SIGURG “Ignore” Notificación de un evento urgente, como la llegada de datos a
través de una interfaz de red.
SIGUSR1 “Terminate” Su aplicación está definida por el programador/usuario.
SIGUSR2 “Terminate” Su aplicación está definida por el programador/usuario.
SIGVTALRM “Terminate” Esta señal se genera por la finalización de un contador virtual
asociado con la función setitimer(…).
SIGXCPU “Terminate+core” Esta señal se canaliza al proceso cuando él excede el uso de CPU
que le ha sido establecido en el sistema.
36. Estructura de un demonio
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
Tres rutinas son esenciales:
#include <unistd.h>
• La rutina principal de inicialización
general.
rutina1 (…) { • Una rutina para inicializar el
… funcionamiento del “daemon”
} • La rutina para recibir señales y
procesarlas en forma conveniente.
rutina2 (…) {
…
Se pueden tener rutinas adicionales de
}
…
soporte e invocaciones a
void signalHandler(int sigNum) {
bibliotecas sin restricciones.
switch(sigNum) {
case SIGHUP:
…
break;
case SIGTERM:
…
break;
37. daemonize()
• Modificar la máscara de creación de archivos invocando a la rutina umask
para evitar heredar dicha característica del proceso principal.
• Clonar el proceso mediante un fork y hacer que el proceso padre finalice.
Esto es útil para hacer simular al “shell” que el proceso ya terminó,
desasociarlo de su terminal, de su usuario/grupo y renunciar a ser el proceso
interactivo (“group leader”).
• Invocar setsid para crear una nueva sesión de trabajo logrando tres cosas:
convertirse en el proceso líder de la sesión, convertirse en el proceso líder de
grupo y renunciar a tener una terminal controladora.
• Cambiar el directorio de facto de trabajo al raíz, evitando así recibirlo
heredado del padre.
• Cerrar todos los descriptores de archivo que pudo haber heredado del
proceso padre.
• Asignar los descriptores de archivo 0, 1 y 2 a /dev/null (stdin, stdout, stderr).
• Asegurarse de ser la única instancia del demonio activo.
• Interceptar señales relevantes y canalizarlas a una rutina de atención.