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

0

Eu escrevi o script de shell abaixo para um laboratório na minha faculdade. Ele deve examinar um arquivo de log sendo atualizado com freqüência de outro processo e criar várias cópias aprovadas no invokation. 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 cada segundo escreve no arquivo log :
 -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 inicio

./logtest.sh &
./logrotate.sh log

o script logrotate.sh move todos os arquivos com os nomes corretos ( log torna-se log.1 ) e envia o sinal para o processo que possui o arquivo log para aquele momento (então o script de shell logtest.sh ) que então continua escrevendo no arquivo log . Além disso, parece que não há diferença sobre qual sinal eu envio com o fusor: ele irá reagir sempre da mesma maneira.

No entanto, se eu iniciar

./logtest &
./logrotate.sh log

acontece que o programa C logtest recebe o sinal do comando fuser e termina.

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

Na página man do fusor, na seção RESTRICTIONS, ele diz

The -k option only works on processes.

Será que os scripts de shell não são considerados processos reais no shell? Isso seria novo para mim ... Eu procurei na Internet, mas nenhuma página encontrada sobre o fuser entra profundamente na seção de sinalização.

    
por Dav Serf 27.05.2015 / 01:41

2 respostas

0

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

Embora isso seja verdade para o programa C , isso não é verdade para o script bash :

echo $(date) >> log

Basta abrir o arquivo, anexar stdout a ele e fechar imediatamente. Portanto, o arquivo nunca é considerado como aberto pelo kernel após a verificação de fuser .

Uma solução simples seria alterar o seu script bash para que o arquivo seja mantido aberto até que o loop while termine:

#! /bin/bash  

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

Dessa forma, um descritor de arquivo para log é criado no início do while do loop e é mantido aberto até o final do loop while .

    
por kos 27.05.2015 / 02:53
1

Seu script logtest.sh só grava em log e fecha o descritor de arquivo imediatamente. Portanto, quando você chamar fuser on log.1 , não haverá um processo que tenha um descritor de arquivo ativo para este arquivo.

Você pode simular isso executando o loop while dentro de um list

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

E ambos logtest.sh e logtest.c serão encerrados, não importa qual SIGNAL você envie porque você não controla o sinal. Com bash , isso pode 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 lerned C).

    
por Germar 27.05.2015 / 02:47