Cómo escribir un proceso de demonio simple
Primero, echemos un vistazo a algunos demonios comunes del sistema y comprendamos su relación con los conceptos de grupos de procesos, terminales de control y sesiones de sesión. El comando p s imprimirá el estado de cada proceso en el sistema. Este comando tiene múltiples opciones; consulte el manual del sistema para obtener más detalles. Para ver la información requerida, ejecute: ps -axj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 0 0 ?-1 S 0 0:04 init
p>1 2 1 1 ? -1 SW 0 0:00 [keventd]
1 3 1 1 ? -1 SW 0 0:00 [kapm-idled]
0 4 1 1 ? -1 SWN 0 0:00 [ksoftirqd_CPU0]
0 5 1 1 ?-1 SW 0 0:00 [kswapd]
0 6 1 1 ? -1 SW 0 0:00 [kreclaimd]
0 7 1 1 ? -1 SW 0 0 0:00 [bdflush]
0 8 1 1 ? 00 [kupdated]
1 9 1 1 ?-1 SW< 0 0:00 [mdrecoveryd]
1 17 1 1 ?-1 SW 0 0:02 [kjournald]
1 92 1 1 ? -1 SW 0 0:00 [khubd]
1 573 573 573 ? p>1 578 578 578 ? -1 S 0 0:00 klogd -2
1 598 598 598 ? -1 S 32 0:00 portmap
Estos procesos están numerados 1 Los procesos de y 2 son muy especiales, existen durante todo el ciclo de vida del sistema. No tienen ID de proceso principal, ID de proceso de grupo ni ID de sesión. El demonio syslogd se puede utilizar con cualquier programa que registre mensajes del sistema para los operadores. sendmail es el demonio de correo estándar. actualizar El programa de actualización escribe periódicamente el contenido de la caché del núcleo en el disco duro (normalmente cada 30 segundos). Para hacer esto, el programa llama a la función sync(2) cada 30 segundos. El demonio cron ejecuta el comando especificado en la fecha y hora especificadas. Muchas tareas de gestión del sistema se implementan mediante la ejecución cron de programas relacionados de forma regular. inetd es un proceso que escucha la interfaz de red del sistema y se utiliza para ingresar solicitudes a varios servidores de red. El demonio final es lpd, que maneja solicitudes de impresión individuales al sistema.
Tenga en cuenta que todos los demonios se ejecutan con prioridad de superusuario (ID de usuario 0). Ninguno de los demonios tiene una terminal de control, el nombre de la terminal está establecido en un signo de interrogación (?) y el ID del grupo de proceso de primer plano de la terminal está establecido en -1. No tener una terminal de control es el resultado de que el demonio llame a setid.
Todos los demonios, excepto los de actualización, son el primer proceso de un grupo de procesos, el primer proceso de una sesión y el único proceso de esos grupos de procesos y sesiones. Una última cosa a señalar es que el proceso padre de todos estos demonios es el proceso de inicio.
Antes de comenzar con la programación real, echemos un vistazo a un concepto que encontrará al escribir un demonio: agrupación de procesos durante una sesión.
Grupo de procesos
Además de tener un ID de proceso, cada proceso también pertenece a un grupo de procesos (los grupos de procesos se presentarán en la discusión sobre señales). Cada proceso tiene un ID de grupo de procesos único. El ID del grupo de procesos es similar al ID del proceso, ambos son números enteros positivos y se pueden almacenar en el tipo de datos pid_t.
Cada grupo de procesos tiene un proceso líder. Un líder de grupo de procesos puede crear un grupo de procesos, crear los procesos en el grupo y luego finalizar esos procesos, independientemente de si su proceso líder finaliza siempre que haya procesos en un grupo de procesos determinado. El intervalo de tiempo desde la creación de un grupo de procesos hasta la salida del último proceso del grupo se denomina ciclo de vida del grupo de procesos. El último proceso de un grupo de procesos puede terminar o unirse a otro grupo de procesos.
Como se mencionó anteriormente, un proceso puede unirse a un grupo de procesos existente o crear un nuevo grupo de procesos llamando a setgid (setid también puede crear un nuevo grupo de procesos, que se usará más adelante)
Ciclo de sesión
Una sesión es una colección de uno o más grupos de procesos. En este caso, hay tres grupos de procesos en una sesión, que generalmente utilizan la tubería del shell para agrupar varios procesos.
A continuación se presentan algunas características de los ciclos de sesión y grupos de procesos:
Un ciclo de sesión puede tener un terminal de control, que suele ser el dispositivo terminal en el que iniciamos sesión (login de terminal) o un dispositivo pseudo terminal (inicio de sesión de red), pero este terminal de control no es necesario.
El primer proceso de una sesión que establece una conexión con el terminal de control se denomina proceso de control. Además, varios grupos de procesos en una sesión se pueden dividir en un grupo de procesos en primer plano y uno o más grupos de procesos en segundo plano.
Si una sesión tiene un terminal de control, entonces tiene un grupo de procesos en primer plano y el otro El grupo de procesos es el grupo de procesos en segundo plano. Siempre que se escribe una tecla de interrupción (normalmente eliminar o Ctrl-c) o una tecla de salida (normalmente Ctrl-/), se envía una señal de interrupción o de salida a todos los procesos del grupo de procesos prometedor.
Reglas de programación para demonios
Los detalles de programación específicos de los demonios no son consistentes en diferentes entornos Unix. Afortunadamente, los principios de programación de demonios son en realidad los mismos, y la diferencia radica únicamente en los detalles de implementación específicos, es decir, para satisfacer las características del demonio. Las reglas de programación son las siguientes:
1. Ejecutar en segundo plano
Para evitar que el terminal de control cuelgue, el proceso del demonio debe ejecutarse en segundo plano llamando a fork en el proceso para finalizar el proceso padre, deje que el proceso demonio ejecute el proceso hijo en segundo plano. Específicamente, llama a fork y luego permite que el proceso padre salga. El propósito de esto es el siguiente:
Primero, si el proceso del demonio se inició con un comando simple, matar el proceso principal hará que el proceso principal piense que el comando se ha ejecutado.
En segundo lugar, el proceso hijo hereda el ID del grupo de procesos del proceso padre, pero tiene un nuevo ID de proceso, lo que garantiza que el proceso hijo no sea el proceso principal del grupo de procesos. Este es un requisito previo necesario para la llamada set e t s i d a continuación.
2. Deshágase del terminal de control, la sesión de inicio de sesión y el grupo de procesos.
La sesión de inicio de sesión puede contener múltiples grupos de procesos, ****, disfrute del terminal de control (generalmente el inicio de sesión). terminal que creó el proceso), terminales de control, sesiones de inicio de sesión y grupos de procesos que generalmente se heredan del proceso principal. El objetivo es deshacerse de ellos para que el proceso no se vea afectado por ellos.
El método específico es llamar a setid() en el primer punto para hacer que el proceso sea el líder de la sesión:
Cabe señalar que cuando el proceso es el líder de la sesión, llame a setid () fallará, pero el primer punto ya asegura que el proceso no es el líder de la sesión.
Después de que la llamada a setid () sea exitosa, el proceso se convertirá en el nuevo líder de sesión y el nuevo líder de grupo de procesos, y se separará de la sesión de inicio de sesión y del grupo de procesos originales. Al mismo tiempo, debido a la exclusividad del proceso de sesión para el. terminal de control, el proceso también se separará de la sesión de inicio de sesión original y el grupo de procesos se separará del terminal de control.
Específicamente, la operación es:
(a) Convertirse en el primer proceso del nuevo período de conversación
(b) Convertirse en el tercer proceso del nuevo proceso El proceso del grupo A
(c) no tiene terminal de control.
3. Evitar que el proceso vuelva a abrir la terminal de control
Ahora, el proceso se ha convertido en el líder del grupo de sesión sin terminal, pero puede volver a solicitar la apertura de la terminal de control. Puede impedir que un proceso vuelva a abrir el terminal de control haciéndolo dejar de ser el líder de la sesión:
4. Cerrar los descriptores de archivos abiertos
Un proceso hereda los descriptores de archivos abiertos del proceso principal que lo creó descriptor de archivo. Si no se cierra, desperdiciará recursos del sistema, provocará que el sistema de archivos donde se encuentra el proceso no pueda desmontarse y provocará errores imprevistos. En términos generales, los descriptores de archivo 0, 1 y 2 deben cerrarse, es decir, entrada estándar, salida estándar y error estándar. Esto se debe a que normalmente queremos que el demonio tenga su propio sistema de entrada y salida de información, en lugar de enviar toda la información a la pantalla del terminal. Llame a fclose();
5. Cambie el directorio de trabajo actual
Cambie el directorio de trabajo actual al directorio raíz. El directorio de trabajo actual heredado del proceso principal puede estar ubicado en un sistema de archivos ensamblado. Debido a que los procesos demonio generalmente persisten hasta que se reinicia el sistema, si el directorio de trabajo actual del proceso demonio está en un sistema de archivos ensamblado, no puede desensamblar el sistema de archivos. Además, algunos procesos demonio pueden cambiar el directorio de trabajo actual a una ubicación designada para su trabajo. Por ejemplo, el proceso demonio pseudo-fuera de línea de la impresora de líneas normalmente cambia su directorio de trabajo a su directorio sp o o l.
Puedes llamar a chdir ("directorio");
6. Restablecer la máscara de creación de archivos
Establece la palabra de la máscara de creación del modo de archivo en 0. Las máscaras de creación de archivos derivadas de la herencia pueden negar la configuración de ciertos permisos. Por ejemplo, si un proceso de sprite desea crear un archivo que sea legible y escribible en grupo, y la palabra de máscara de creación del modo de archivo heredada bloquea ambos permisos, el proceso de lectura y escritura en grupo requerido no funcionará.
7. Procesando la señal SIGCHLD
No es necesario procesar la señal SIGCHLD. Sin embargo, para algunos procesos, especialmente los procesos del servidor, a menudo se genera un proceso hijo cuando llega una solicitud. Si el proceso padre no espera a que finalice el proceso hijo, el proceso hijo se convertirá en un zombi y seguirá ocupando recursos del sistema. Si el proceso principal espera a que finalice el proceso secundario, aumentará la carga sobre el proceso principal y afectará el rendimiento de concurrencia del proceso del servidor. En el Sistema V, solo necesita configurar la operación de la señal SIGCHLD en SIG-IGN:
signal(SIGCHLD,SIG_IGN);
De esta manera el kernel no generará un zombie. proceso, a diferencia de BSD4 donde tenías que indicar que estabas esperando a que finalizara el proceso hijo antes de liberar el proceso zombie.
Ejemplo de proceso demonio
El ejemplo de proceso demonio consta de dos partes: el programa principal test.c y el programa de inicialización init.c. El programa principal informa el estado cada minuto al registro test.log en el directorio /tmp.
La función init_daemon en el programa de inicialización es responsable de iniciar el proceso del demonio
void make_daemon(void)
{
pid_t pid;
ARCHIVO * lockfd ;
sigset_t sighup;
int i;
pid_t externo getsid(pid_t);
pid = fork( );// se genera el primer proceso hijo
if (pid < 0) {
printinfo("¡error de bifurcación!",INFOERROR
exit(FAILEXIT); );
p>}else if (pid > 0) {
printinfo("fork 1 ok!", INFOSCREEN);
salir(OKEXIT) ;//salir del proceso padre y salir del control del shell
}
pid = getpid();//obtener la identificación del proceso hijo en sí
lockfd = fopen(PIDFILE, "w");//lo siguiente escribe el pid en el archivo
if (lockfd != NULL) {
fprintf (lockfd, "%d /n", pid);
fclose(lockfd);
}// Escribir pid
if (getsid(0) != pid) { //Crear un nuevo período de sesión
if (setsid() < 0) {
printinfo("backupdaemon setsid error!",INFOERROR);
error( "setid");
}
}
if(pid=fork()){// Generar un proceso hijo nuevamente , esta vez un proceso nieto
exit(0); //salir del proceso de generación anterior
}else if(pid<0){
exit( 1);
}
close(1);//Cerrar el archivo
close(2);
chdir(rundir );//Cambiar el directorio de ejecución
umask(022);//Cambiar permisos de archivos
}
El demonio de salida de errores del demonio no pertenece a ningún terminal, por lo que cuando necesita generar algo de información es hora. No puede enviar información directamente a la salida estándar y al error estándar como los programas normales. Tampoco queremos que cada demonio escriba su propia información de error en un archivo separado. Esto sería un dolor de cabeza para los administradores de sistemas, ya que tienen que recordar qué demonio escribió información en qué archivos de registro y verificar periódicamente esos archivos. Por lo tanto, necesitamos un mecanismo centralizado de registro de errores del demonio. Ahora, muchos sistemas han introducido el proceso de registro syslog para lograr este propósito. La mayoría de los demonios utilizan el mecanismo syslog BSD desde su desarrollo y uso generalizado en Berkeley. A continuación presentaremos el uso de BSD syslog. Hay tres formas de generar mensajes de registro:
1 Las rutinas del kernel pueden llamar a funciones de registro. Cualquier proceso de usuario puede leer estos mensajes abriendo y leyendo el dispositivo /dev/klog.
Como no planeamos escribir la rutina en el kernel, no describiremos esta función más.
2 La mayoría de los procesos de usuario (procesos demonio) llaman a la función syslog para generar información de registro. Describiremos la secuencia de llamadas a continuación.
3 Los procesos de usuario en este host u otros hosts conectados a este host a través de una red TCP/IP pueden enviar información de registro al puerto UDP 514. Nota: La función syslog no genera estos datagramas UDP. -Requieren una programación de red explícita por parte del proceso que genera la información de registro. Normalmente, el demonio syslog lee la información de registro en tres formatos. El demonio lee el archivo de configuración al inicio. Este archivo suele denominarse /etc/syslog.conf y determina dónde se envían los diferentes tipos de información. Por ejemplo, los mensajes de emergencia se pueden enviar al administrador del sistema (si está conectado) y mostrarse en la consola, mientras que los mensajes de advertencia se pueden registrar en un archivo. Este mecanismo proporciona la función syslog, cuyo formato de llamada es el siguiente
#include
void openlog (char*ident,int option,int facility);
void syslog (int prioridad, formato char*,...)
void closelog();
Llamar a openlog es opcional. Llamar a closelog también es opcional y simplemente cierra el descriptor utilizado para la comunicación con el demonio syslog. Llamar a openlog nos permite especificar un identificador que luego se agregará a cada mensaje de registro. El identificador suele ser el nombre del programa (como cron, inetd, etc.): LOG_CONS Si la información de registro no se puede enviar a syslog a través de datagramas de dominio Unix, la información se escribirá en la consola. LOG_NDELAY1 Abre inmediatamente un socket de datagrama de dominio Unix al demonio syslog sin esperar a que se registre el primer mensaje. LOG_PERROR Envía información de registro a syslog además del error estándar. Esta opción sólo es compatible con 4.3BSDReno y superiores. LOG_PID Cada mensaje contiene el ID del proceso. Esta opción se puede utilizar para bifurcar el demonio en un proceso secundario para cada solicitud. El propósito de configurar el parámetro de instalación en openlog es permitir que el archivo de configuración indique que los mensajes de diferentes instalaciones se procesarán de manera diferente. Si no se llama a openlog, o se llama con la función 0, la función se puede especificar como parte del parámetro de prioridad al llamar a syslog. Llamar a syslog generará un mensaje de registro. El parámetro de prioridad es una combinación de instalación y nivel, y los valores disponibles para cada parámetro se enumeran a continuación: Los valores de nivel están ordenados de mayor a menor prioridad.