Per gestire nomi di file arbitrari (compresi quelli che contengono caratteri di nuova riga), il solito trucco è trovare i file all'interno .//.
anziché .
. Poiché //
normalmente non può verificarsi durante l'attraversamento dell'albero delle directory, si è certi che a //
segnali l'inizio di un nuovo nome file nell'output find
(o qui 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()}'
Si noti che l'output sarà comunque separato da nuova riga. Se è necessario post-elaborarlo, è necessario adattarlo. Ad esempio, potresti aggiungere a -v ORS='\0'
per poterlo alimentare su GNU xargs -r0
.
Si noti inoltre che lsattr -R
(almeno 1.42.13) non è possibile segnalare i flag di file il cui percorso è più grande di PATH_MAX (in genere 4096), quindi qualcuno potrebbe nascondere un file così immutabile spostando la sua directory principale (o qualsiasi componente del percorso che porta a esso, tranne se stesso in quanto è immutabile) in una directory molto profonda.
Una soluzione sarebbe usare find
con -execdir
:
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
Ora, con -print0
, è post-processabile, ma se si intende fare qualcosa con quei percorsi, si noti che qualsiasi chiamata di sistema su percorsi di file superiori a PATH_MAX fallirebbe comunque e che i componenti della directory avrebbero potuto essere rinominati nell'intervallo.
Se vogliamo ottenere un rapporto affidabile su un albero di directory potenzialmente scrivibile da altri, ci sono alcuni altri problemi inerenti al lsattr
comando stesso che dovremmo menzionare:
- il modo in cui
lsattr -R .
attraversa l'albero delle directory, è soggetto alle condizioni di gara. Si può far scendere le directory all'esterno dell'albero delle directory indirizzate .
sostituendo alcune directory con collegamenti simbolici al momento giusto.
lsattr -d file
ha persino una condizione di gara. Tali attributi sono applicabili solo a file o directory regolari. Quindi lsattr
fa un lstat()
primo controllo per verificare che il file sia dei tipi giusti e quindi open()
seguito ioctl()
per recuperare gli attributi. Ma chiama open()
senza O_NOFOLLOW
(né O_NOCTTY). Qualcuno potrebbe sostituire file
con un collegamento simbolico, ad /dev/watchdog
esempio, tra lstat()
e open()
e far riavviare il sistema. Dovrebbe essere open(O_PATH|O_NOFOLLOW)
seguito da fstat()
, openat()
e ioctl()
qui per evitare le condizioni di gara.