Restaurando um arquivo aberto

5

Eu tenho um problema interessante que pode ou não ter uma solução, mas eu adoraria ter um problema, se possível:

No Solaris, um arquivo de log aberto foi removido, que ainda continua sendo preenchido enquanto o processo está em execução, mas agora está inacessível para todas as outras ferramentas, como cat , tail , etc.

Existe alguma maneira de restaurar a entrada no diretório para este arquivo enquanto tudo continua em execução?

    
por Karlson 04.04.2012 / 16:18

1 resposta

6

Isso é possível, com alguns hacks e limitações (você precisa de privilégios de root).

Primeiro, encontre o descritor de arquivo que está usando o aplicativo para gravar o arquivo de registro e crie um link simbólico no local do arquivo de log anterior e aponte para a entrada de arquivo / proc, por exemplo:

ln -s /var/tmp/file.log /proc/12345/fd/3

A primeira limitação é que, se o arquivo estiver aberto apenas para gravação pelo processo, sua permissão não permitirá que um usuário sem privilégios leia seu conteúdo. No entanto, root e usuários com o privilégio file_dac_read não serão afetados. Como alternativa, você pode usar um processo para copiar o conteúdo do arquivo com tail , como Gilles está sugerindo em seu comentário. por exemplo:

tail -c +1 -f /proc/12345/fd/5 > /var/tmp/file.log

A segunda questão é que todo o conteúdo do arquivo será perdido ( ln -s ) ou parte dele ( tail -c 1 -f ) quando o processo for fechado ou sair.

Uma solução alternativa é usar um programa que monitore esse evento e fazer o backup do arquivo antes que o fechamento seja realmente chamado.

As ferramentas prováveis para realizar o trabalho são dtrace, truss, mdb ou dbx.

Aqui está uma prova de conceito usando o dtrace no Solaris 10.

#!/bin/ksh
#
# This dtrace script is monitoring a file descriptor for a given process
# and copy its content to the given path when the file is closed.
#

pid=${1:?"$0: Usage: pid fd path"}
fd=${2:?}
path=${3:?}
[[ -f $path ]] && { echo "$path exists"; exit 1; }
dtrace -w -n '
syscall::close:entry
/pid=='$pid' && arg0=='$fd'/
{
        stop();
        system("cp /proc/%d/fd/%d %s",pid,arg0,"'"$path"'");
        system("prun %d",pid);
        exit(0);
}'
    
por 05.04.2012 / 08:36