Para tratar con nombres de archivos arbitrarios (incluidos los que contienen caracteres de nueva línea), el truco habitual es encontrar archivos dentro en .//.
lugar de .
. Como //
normalmente no puede ocurrir al atravesar el árbol de directorios, está seguro de que //
indica el inicio de un nuevo nombre de archivo en la salida find
(o aquí 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()}'
Tenga en cuenta que la salida seguirá estando separada por una nueva línea. Si necesita procesarlo posteriormente, deberá adaptarlo. Por ejemplo, podría agregar un -v ORS='\0'
para poder alimentarlo a GNU xargs -r0
.
También tenga en cuenta que lsattr -R
(al menos 1.42.13) no puede informar los indicadores de archivos cuya ruta es más grande que PATH_MAX (generalmente 4096), por lo que alguien podría ocultar un archivo tan inmutable moviendo su directorio principal (o cualquiera de los componentes de ruta que conducen a , excepto en sí mismo, ya que es inmutable) en un directorio muy profundo.
Una solución alternativa sería usar find
con -execdir
:
find . -execdir sh -c '
a=$(lsattr -d "$1") &&
case ${a%% *} in
(*i*) ;;
(*) false
esac' sh {} \; -print0
Ahora, con -print0
, eso es postprocesable, pero si tiene la intención de hacer algo con esas rutas, tenga en cuenta que cualquier llamada al sistema en rutas de archivos mayores que PATH_MAX todavía fallaría y los componentes del directorio podrían haber cambiado de nombre en el intervalo.
Si queremos obtener un informe confiable sobre un árbol de directorios que otros usuarios puedan escribir, hay algunos problemas más inherentes al lsattr
comando en sí que deberíamos mencionar:
- la forma en que
lsattr -R .
atraviesa el árbol de directorios está sujeto a condiciones de carrera. Uno puede hacer que descienda a directorios fuera del árbol de directorios enrutado .
reemplazando algunos directorios con enlaces simbólicos en el momento correcto.
- incluso
lsattr -d file
tiene una condición de carrera. Esos atributos solo son aplicables a archivos o directorios normales. Así que lsattr
hace un lstat()
primero para comprobar que el archivo es de los tipos correctos y luego no open()
siguió ioctl()
para recuperar los atributos. Pero llama open()
sin O_NOFOLLOW
(ni O_NOCTTY). Alguien podría reemplazar file
con un enlace simbólico, /dev/watchdog
por ejemplo, entre lstat()
y open()
y hacer que el sistema se reinicie. Debe hacerlo open(O_PATH|O_NOFOLLOW)
seguido fstat()
, openat()
y ioctl()
aquí para evitar las condiciones de carrera.