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.sh
apenas grava log
e fecha o descritor de arquivo imediatamente. Portanto, quando você liga fuser
, log.1
não há nenhum processo que tenha um descritor de arquivo ativo para esse arquivo.
Você pode simular isso executando o while
loop dentro de umlist
(while true; do echo $(date); sleep 1; done) >> log
E ambos logtest.sh
e logtest.c
terminarão independentemente do que SIGNAL
você enviar, porque você não controla o sinal. Isso bash
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 aprendi C).
Responder2
O problema é que fuser
só 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 C
programa, não é verdade para o seu bash
script:
echo $(date) >> log
Basta abrir o arquivo, anexa- stdout
lo e fechá-lo imediatamente. Portanto, o arquivo nunca é considerado aberto pelo kernel na fuser
verificação.
Uma solução simples seria alterar seu bash
script para que o arquivo fique aberto até o while
final do loop:
#! /bin/bash
while true
do
echo $(date) >> log
sleep 1
done < log
Desta forma, um descritor de arquivo for log
é criado no while
início do loop e é mantido aberto até o while
final do loop.