Para lidar com nomes de arquivos arbitrários (incluindo aqueles que contêm caracteres de nova linha), o truque usual é encontrar arquivos dentro deles, em .//.
vez de .
. Como //
normalmente não pode ocorrer ao percorrer a árvore de diretórios, você tem certeza de que um //
sinaliza o início de um novo nome de arquivo na saída find
(ou aqui lsattr -R
).
lsattr -R .//. | awk '
function process() {
i = index(record, " ")
if (i && index(substr(record,1,i), "i"))
print substr(record, i+4)
}
{
if (/\/\//) {
process()
record=$0
} else {
record = record "\n" $0
}
}
END{process()}'
Observe que a saída ainda será separada por nova linha. Se você precisar pós-processá-lo, precisará adaptá-lo. Por exemplo, você pode adicionar um -v ORS='\0'
para poder alimentá-lo nos GNUs xargs -r0
.
Observe também que lsattr -R
(pelo menos 1.42.13) não pode relatar os sinalizadores de arquivos cujo caminho é maior que PATH_MAX (geralmente 4096), para que alguém possa ocultar um arquivo imutável movendo seu diretório pai (ou qualquer um dos componentes do caminho que levam a , exceto a si mesmo, pois é imutável) em um diretório muito profundo.
Uma solução alternativa seria usar find
com -execdir
:
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
Agora, com -print0
, isso é pós-processável, mas se você pretende fazer algo com esses caminhos, observe que qualquer chamada do sistema em caminhos de arquivo maiores que PATH_MAX ainda falhará e os componentes do diretório poderão ter sido renomeados no intervalo.
Se quisermos obter um relatório confiável em uma árvore de diretórios potencialmente gravável por outras pessoas, existem mais alguns problemas inerentes ao lsattr
próprio comando que precisaríamos mencionar:
- a maneira como
lsattr -R .
percorre a árvore de diretórios, está sujeita às condições de corrida. Pode-se descer para diretórios fora da árvore de diretórios roteados .
substituindo alguns diretórios por links simbólicos no momento certo.
- ainda
lsattr -d file
tem uma condição de corrida. Esses atributos são aplicáveis apenas a arquivos ou diretórios regulares. O mesmo lsattr
acontece lstat()
primeiro para verificar se o arquivo é do tipo certo e, em seguida, é open()
seguido por ioctl()
para recuperar os atributos. Mas chama open()
sem O_NOFOLLOW
(nem O_NOCTTY). Alguém poderia substituir file
com um link simbólico para /dev/watchdog
, por exemplo, entre o lstat()
e open()
e causa a reinicialização do sistema. Deve fazer open(O_PATH|O_NOFOLLOW)
seguido por fstat()
, openat()
e ioctl()
aqui para evitar as condições da corrida.