Diferencia entre programas C y scripts de shell que reciben señales del fusor

Diferencia entre programas C y scripts de shell que reciben señales del fusor

Escribí el siguiente script de shell para un laboratorio de mi universidad. Debe observar un archivo de registro que se actualiza con frecuencia desde otro proceso y crear una cantidad de copias pasadas durante la invocación. Aquí está el código (logrotate.sh):

#!/bin/bash

# Usage:
#   logrotate.sh [-n int] [-s signal] logfile
# where:
#   int is an optional integer used to make int number of copies of logfile
#   signal is the name of signal which shell command fuser must send to the process managing logfile
# this script lacks of a strong parameters checking

NCOPIES=4  
LOGSIGNAL=USR1

#use of getopts to parse the arguments  
while getopts "n:s:" OPTION ; do  
    case $OPTION in  
        n) NCOPIES="$OPTARG"  
           ;;  
        s) LOGSIGNAL="$OPTARG"  
           ;;  
        ?) printf "Usage: %s [-n copies to keep] [-s signal to send] filename\n" $(basename $0) >&2  
        exit 1  
           ;;  
    esac  
done  
#shift to read the last parameter (logfile)  
shift $(($OPTIND - 1))  
LOGFILE=$1  

#create logfile.2 logfile.3 ... logfile.NCOPIES  
for i in `seq $NCOPIES -1 1` ; do  
    test -f $LOGFILE.$i && mv $LOGFILE.$i $LOGFILE.$[ $i + 1 ]  
done  

mv $LOGFILE $LOGFILE.1  

#sending signal to process which is writing to logfile to keep on writing to $LOGFILE(original name, without any extensions)  
fuser -k -"$LOGSIGNAL" $LOGFILE.1  

Entonces escribí dos scripts que cada segundo escriben en el archivo.registro:
-el programa C (logtest.c):

#include <stdio.h>  
#include <stdlib.h>   
#include <fcntl.h>  
#include <unistd.h>  

int main()  
{  
    int fd = open("log", O_WRONLY | O_APPEND);  
    if(fd < 0 ){  
        printf("Impossible to open file %s.\n", "log");  
        return -1;  
    }  
    for(;;){  
        if(write(fd, "Ciao bello mio\n", 15) != 15){  
            write(2, "Error in writing data.\n", 23);  
        }  
        sleep(1);  
    }  
    close(fd);  
    exit(0);  
}  

-y el script de shell (logtest.sh):

#! /bin/bash  

while true 
do
    echo $(date) >> log
    sleep 1
done  

cuando lanzo

Registro ./logtest.sh y
./logrotate.sh

la secuencia de comandoslogrotate.shmueve todos los archivos con los nombres correctos (registrose convierteregistro.1) y envía la señal al proceso propietario del archivoregistropara ese momento (por lo que el script de shelllogtest.sh) que luego sigue escribiendo en el archivoregistro. Además, parece que no hay diferencia en cuanto a qué señal envío con el fusor: reaccionará siempre de la misma manera.

Sin embargo, si lanzo

./logtest y
./logrotate.sh registro

sucede que el programa Cprueba de registrorecibe la señal del comandofusory luego termina.

Mi pregunta es: ¿por qué los dos programas de registro tienen reacciones diferentes a la señal enviada desde el fusor? Quiero decir, ¿por qué el script Schell sigue funcionando mientras el programa C finaliza?

En la página de manual del fusor en la sección RESTRICCIONES dice

La opción -k solo funciona en procesos.

¿Podría ser que los scripts de Shell no se consideren procesos reales en el Shell? Esto sería nuevo para mí... He buscado en Internet pero no encontré ninguna página sobrefusorprofundizar en la sección de señalización.

Respuesta1

Su secuencia de comandos logtest.shsolo escribe logy cierra el descriptor de archivo inmediatamente. Entonces, cuando llama fuser, log.1no hay ningún proceso que tenga un descriptor de archivo activo para este archivo.

Puedes simular esto ejecutando el whilebucle dentro de unlist

(while true; do echo $(date); sleep 1; done) >> log

Y ambos logtest.shy logtest.cterminarán sin importar cuál SIGNALenvíe porque no maneja la señal. Con bashesto se puede hacer con trap '<COMMAND>' USR1(eche un vistazo a man bash-builtins). Pero no tengo idea de cómo se hace esto en C (nunca aprendí C).

Respuesta2

El problema es que fusersolo funciona en procesos que actualmente usan un archivo que tiene un descriptor de archivo abierto en el kernel.

Si bien esto es cierto para su Cprograma, no lo es para su bashscript:

echo $(date) >> log

Simplemente abre el archivo, stdoutlo agrega y lo cierra inmediatamente. Por lo tanto, el kernel nunca considera que el archivo ha sido abierto tras fuserla verificación.

Una solución simple sería cambiar su bashscript para que el archivo se mantenga abierto hasta que whilefinalice el ciclo:

#! /bin/bash  

while true 
do
    echo $(date) >> log
    sleep 1
done < log

logDe esta manera , se crea un descriptor de archivo al whileinicio del ciclo y se mantiene abierto hasta el whilefinal del ciclo.

información relacionada