El estándar de shell POSIX dice en este sitio
http://pubs.opengroup.org/onlinepubs/9699919799/
sobre cómo usan los shells PATH
para buscar ejecutables:
"Se buscará en la lista de principio a fin, aplicando el nombre de archivo a cada prefijo, hasta que se encuentre un archivo ejecutable con el nombre especificado y los permisos de ejecución apropiados".
Bueno, no es así como parece funcionar en la implementación POSIX real:
man which
dice:
"devuelve los nombres de ruta de los archivos (o enlaces) que se ejecutarían en el entorno actual, si sus argumentos se hubieran dado como comandos en un shell estrictamente compatible con POSIX. Lo hace buscando en la RUTA archivos ejecutables que coincidan con los nombres de argumentos. No sigue enlaces simbólicos ".
OK, veamos esta situación:
$ pwd
/home/mark
$ echo $PATH
/home/mark/bin:
...
$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar
OK, aquí hay un enlace simbólico PATH
con el nombre correcto, y se informa ls
que es ejecutable.
which
no lo mira en absoluto, pero solo le interesa lo que señala.
Eso a pesar del hecho de que ambos man which
dicen explícitamente que no sigue enlaces simbólicos (y de hecho vemos que no lo hace, porque which foobar
no se imprime foobar1
), y también que la documentación del shell POSIX citada anteriormente, nunca menciona los siguientes enlaces simbólicos en el PATH
algoritmo.
Entonces, ¿están which
mal los shells existentes o no entiendo la documentación?
PARA ACLARAR:
Sé y puedo explicar el comportamiento existente. Mi pregunta no es "¿cómo funciona esto?". Eso lo sé.
Mi pregunta es sobre la documentación: ¿dónde está mi error al seguir la documentación que cité? ¿O está mal la documentación?
MOTIVACIÓN: ¿Por qué me importa?
Bueno, soy un implementador. Los diferentes implementadores tienen diferentes requisitos. Para mí, el requisito es que la palabra del estándar POSIX actual DEBE seguirse EXACTAMENTE (o, más precisamente, lo mejor que puede ser, porque el estándar en sí es algo defectuoso). Como si fuera la palabra de Dios.
Ahora, la redacción estándar es bastante clara: no se mencionan los enlaces simbólicos, donde en muchos otros lugares, se menciona dónde debe hacerse. Entonces, en este caso, no lo hagas.
Sin embargo, siempre verifico cómo dash
y cómo me bash
comporto, solo para asegurarme. Ahora, por supuesto, también hay un pequeño problema aquí, dash
aunque se factura como POSIX, tiene muchos pequeños errores conformes con POSIX. bash
, Todavía no he encontrado ningún error con POSIX, pero ... bash no es realmente POSIX, es mucho más que eso.
Entonces ahí lo tienes. Por eso me importa.
fuente
$PATH
lata contiene enlaces simbólicos. Tratarwhich sh
.$PATH
no tiene enlaces simbólicos.lstat(2)
), por lo general, no se indica su seguimiento. Por ejemplo, la descripción deopen(2)
solo menciona enlaces simbólicos cuando se habla del comportamiento deO_CREAT | O_EXCL
. No es necesario indicar que se abrirá el archivo de destino.Respuestas:
Los permisos del enlace simbólico en sí son irrelevantes. Ni siquiera podría cambiarlos si lo intentara.
Lo que importa son los permisos del archivo subyacente.
Está bien que los directorios en su RUTA incluyan enlaces simbólicos a ejecutables. De hecho, es probable que muchos ejecutables en su RUTA sean enlaces simbólicos. Por ejemplo, en sistemas debian / ubuntu-like:
Documentación
De
man chmod
:Ejemplo
El shell tiene una prueba,
-x
para determinar si un archivo es ejecutable. Probemos eso:Entonces, tal como lo encontró con
which
, el shell no considera un ejecutable softlink a menos que el archivo subyacente sea ejecutable.Como funciona
En un sistema Debian,
which
es un script de shell. La sección relevante del código es:Como puede ver, utiliza la
-x
prueba para determinar si un archivo es ejecutable.POSIX especifica la
-x
prueba de la siguiente manera:Entonces, POSIX verifica a qué se resuelve el nombre de ruta . En otras palabras, acepta enlaces simbólicos.
Función de ejecución POSIX
La función de ejecución POSIX sigue enlaces simbólicos. La especificación POSIX continúa para especificar las condiciones de error que puede informar si los enlaces simbólicos son circulares o demasiado profundos, como:
fuente
which
es un script de shell. Por lo tanto, es probable que solo esté usando la-x
prueba que mostré. Según POSIX,-x
prueba si un archivo "se resuelve" en un ejecutable. Si estás viendo algo diferente, ¿dónde estás mirando?which
funciona, o si es-x
o algo más. Me interesa saber dónde no sigo correctamente la documentación que cité.exec
sigue enlaces simbólicos. Eso parece dejar bastante claro que los archivos con enlaces simbólicos pueden ser ejecutables en POSIX.man which
que dice "No canonicaliza los nombres de ruta". Eso no significa que no siga los enlaces. Eso solo significa, como observó, que no "canoniza" los nombres.En este caso, los enlaces simbólicos se siguen de forma transparente, sin canonizar la ruta final. En otras palabras,
which
no le importa si/home/mark/bin
es un enlace simbólico o no. Lo que le importa es si el archivo/home/mark/bin/foobar
existe o no. No necesita aplanar manualmente los enlaces simbólicos a lo largo de la ruta; el sistema operativo puede hacerlo bien solo.Y, de hecho, cuando se
which
le pregunta acerca de la información del archivo/home/mark/bin/foobar
, el sistema operativo nota que/home/mark/bin
es un enlace simbólico, lo sigue y lo encuentra con éxitofoobar
en el directorio de destino.Este es el comportamiento predeterminado a menos que el programa use
open(…, O_NOFOLLOW)
ofstatat(…, AT_SYMLINK_NOFOLLOW)
para acceder al archivo.[comentarios fusionados en]
Si bien se dice que las utilidades de shell lo hacen sobre una base caso por caso, no es lo mismo con llamadas al sistema del kernel: todas las llamadas de archivos relacionados hacen seguir enlaces simbólicos por defecto, a menos que se da la opción "nofollow". (Incluso lstat sigue enlaces simbólicos en todos los componentes de la ruta excepto el último).
Cuando la especificación no menciona explícitamente qué hacer con los enlaces simbólicos, implica que se utilizará el comportamiento predeterminado. Es decir, un shell que sigue el algoritmo de ruta no resuelve los enlaces simbólicos manualmente ni excluye explícitamente que el sistema operativo haga lo mismo. (Simplemente concatena cada componente $ PATH con el nombre ejecutable).
Cuando la página del manual which (1) dice que no sigue enlaces simbólicos, puede significar varias cosas, pero la versión de GNU coreutils lo dice de esta manera:
El alcance es mucho más limitado: solo significa
which
que no intentará canonizar manualmente todas las rutas para eliminar los duplicados, pero no implica que la herramienta optará por el enlace simbólico que sigue el sistema operativo en general. Por ejemplo, si/bin
es un enlace simbólico a/usr/bin
, la ejecuciónwhich -a sh
devolverá ambos/bin/sh
y/usr/bin/sh
.fuente
which
página del manual de GNU lo expresa de manera diferente: "Lo que considerará que dos directorios equivalentes son diferentes cuando uno de ellos contiene una ruta con un enlace simbólico".execve("/home/mark/bin/foobar", …)
, dará como resultado que se sigan todos los enlaces simbólicos.execve
argumento, en realidad, en mi implementación, es loexecl()
mismo. Por favor, si incluye esto en su respuesta, lo aceptaré.El shell se ajusta a su documentación en el sentido de que sigue las reglas para la resolución del nombre de ruta.
which
se ajusta a su documentación. Los dos hacen cosas ligeramente diferentes.La salida de
which
es el nombre y la ruta del archivo del enlace, no la ruta a la que apunta el enlace simbólico. Esto se explica en la página del manual.Cuando se ejecuta un comando, el enlace se "sigue" según la Sección 4.13 Resolución de nombre de ruta en el mismo . La cláusula relevante para ejecutar un archivo es:
fuente