Diferença entre programas C e scripts shell que recebem sinais do fusor

Diferença entre programas C e scripts shell que recebem sinais do fusor

Escrevi o script de shell abaixo para um laboratório em minha faculdade. Ele deve examinar um arquivo de log que está sendo atualizado frequentemente de outro processo e criar um número de cópias passadas na invocação. Aqui está o 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  

Então eu escrevi dois scripts que a cada segundo gravam no arquivoregistro:
-o 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);  
}  

-e o script de shell (logtest.sh):

#! /bin/bash  

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

Quando eu lançar

./logtest.sh e
./logrotate.sh log

o roteirologrotate.shmove todos os arquivos com os nomes corretos (registrotorna-seregistro.1) e envia o sinal para o processo que possui o arquivoregistropara aquele momento (então o shell scriptlogtest.sh) que continua escrevendo no arquivoregistro. Além disso, parece que não há diferença sobre qual sinal eu envio com o fusor: ele reagirá sempre da mesma maneira.

No entanto, se eu lançar

./logtest &
./logrotate.sh log

acontece que o programa Cteste de registrorecebe o sinal do comandofusore então termina.

Minha pergunta é: por que os dois programas de registro têm reações diferentes ao sinal enviado pelo fusor? Quero dizer, por que o script schell continua funcionando enquanto o programa C termina?

Na página de manual do fusor na seção RESTRIÇÕES, diz

A opção -k funciona apenas em processos.

Será que os scripts de shell não são considerados processos reais no shell? Isso seria novo para mim... Pesquisei na Internet, mas não encontrei nenhuma página sobrefusorvá fundo na seção de sinalização.

Responder1

Seu script logtest.shapenas grava loge fecha o descritor de arquivo imediatamente. Portanto, quando você liga fuser, log.1não há nenhum processo que tenha um descritor de arquivo ativo para esse arquivo.

Você pode simular isso executando o whileloop dentro de umlist

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

E ambos logtest.she logtest.cterminarão independentemente do que SIGNALvocê enviar, porque você não controla o sinal. Isso bashpode ser feito com trap '<COMMAND>' USR1(dê uma olhada em man bash-builtins). Mas não tenho ideia de como isso é feito em C (nunca aprendi C).

Responder2

O problema é que fusersó funciona em processos que atualmente usam um arquivo que possui um descritor de arquivo aberto para eles no kernel.

Embora isso seja verdade para o seu Cprograma, não é verdade para o seu bashscript:

echo $(date) >> log

Basta abrir o arquivo, anexa- stdoutlo e fechá-lo imediatamente. Portanto, o arquivo nunca é considerado aberto pelo kernel na fuserverificação.

Uma solução simples seria alterar seu bashscript para que o arquivo fique aberto até o whilefinal do loop:

#! /bin/bash  

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

Desta forma, um descritor de arquivo for logé criado no whileinício do loop e é mantido aberto até o whilefinal do loop.

informação relacionada