¿Por qué tenemos que pasar el nombre del archivo dos veces en las funciones ejecutivas?


11

He leído Programación avanzada en el entorno UNIX por Stevens, 8 º capítulo. Leo y entiendo las seis funciones ejecutivas.

Una cosa que noto es, en todas las funciones ejecutivas:

  • El primer argumento es el nombre del archivo / nombre de ruta (depende de la función ejecutiva).
  • El segundo argumento es argv [0] en el que ingresamos main(), que es el nombre del archivo en sí.

Entonces aquí tenemos que pasar el nombre del archivo dos veces en la función.

¿Hay alguna razón para ello (como que no podemos obtener el nombre del archivo desde el nombre de la ruta desde el primer argumento)?

Respuestas:


14

Entonces aquí tenemos que pasar el nombre del archivo dos veces en la función.

No son exactamente lo mismo que observa al observar que uno de ellos se usa como argv[0]valor. Esto no tiene que ser el mismo que el nombre base del ejecutable; muchas / la mayoría de las cosas lo ignoran y puedes poner lo que quieras allí.

El primero es la ruta real al ejecutable, para lo cual existe una necesidad obvia. El segundo se pasa al proceso aparentemente como el nombre utilizado para invocarlo, pero, por ejemplo:

execl("/bin/ls", "banana", "-l", NULL);

Funcionará bien, suponiendo que /bin/lses el camino correcto.

Algunas aplicaciones, sin embargo, hacen uso de argv[0]. Por lo general, estos tienen uno o más enlaces simbólicos en $PATH; Esto es común con las utilidades de compresión (a veces usan envoltorios de shell). Si lo ha xzinstalado, stat $(which xzcat)muestra que es un enlace xzy man xzcates el mismo man xzque explica "xzcat es equivalente a xz --decompress --stdout". La forma en que xz puede determinar cómo se invocó es comprobando argv[0], haciendo estos equivalentes:

execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);

44
Ah, entonces esto explicaría cómo busyboxpuede ser lo que quieres que sea, dependiendo de cómo lo llames, ¿verdad?
terdon

3
@terdon así es exactamente como el binario único para busybox satisface tantos comandos diferentes.
mah

77
Lo que significaría que si /bin/lsfuera busybox, ¡no sabría cómo ejecutar banana!
Riking

6

No tiene que pasar el nombre del archivo dos veces.

El primero es el archivo que realmente está ejecutado.

El segundo argumento es lo que debería ser el argv[0]proceso, es decir, lo que el proceso debería ver como su nombre. Por ejemplo, si se ejecuta lsdesde el shell, el primer argumento es /bin/ls, el segundo es justo ls.

Puede ejecutar un determinado archivo y llamarlo de otra manera a través del segundo argumento; el programa puede verificar su nombre y comportarse de manera diferente según el nombre. Esto también se puede hacer a través de enlaces duros (o enlaces simbólicos) pero de esta manera se da más flexibilidad.


De hecho, los enlaces son el mismo método, ya que se establece argv[0]en el nombre del enlace.
Ricitos de Oro

En el último párrafo, "Puede ejecutar un determinado archivo y llamarlo de otra manera a través del segundo argumento; el programa puede verificar su nombre y comportarse de manera" diferente "según el nombre". ¿Puede por favor elaborar o darme algunas lecturas? Soy nuevo en este entorno.
munjal007

La última parte de la respuesta de Ricitos de Oro explica esto.
wurtel

1

La conclusión es que argv[0]se puede establecer en cualquier cosa (incluido NULL). Por convención , argv[0]se establecerá en la ruta en la que se inició el ejecutable (por el proceso de shell cuando lo hace execve()).

Si ./fooy dir/barson dos enlaces diferentes (duros o simbólicos) al mismo ejecutable, entonces el inicio del programa desde el shell utilizando las dos rutas se establecerá argv[0]en ./fooy dir/bar, respectivamente.

El hecho de que argv[0]puede ser a NULLmenudo se pasa por alto. El siguiente código podría bloquearse para un NULL argv[0]por ejemplo (aunque glibc imprime algo como <null> en su lugar argv[0]):

if (argc != 3) {
    fprintf(stderr, "%s: expected 2 arguments\n", argv[0]);
    exit(EXIT_FAILURE);
}

Una alternativa en Linux es usar /proc/self/exepara tales casos.


¿cómo se puede conjunto argv [0] para ambos ./foo y dir / bar
munjal007

@ munjal007 Lo siento si no estaba claro. Me refería a ejecutar el programa dos veces: una vez ./fooy una vez como dir/bar. argv[0]será diferente para esos dos casos (en cada caso será la misma que la ruta que utilizó).
Ulfalizer

@ munjal007 Eso, suponiendo que lo ejecutes desde el shell, por supuesto. El punto es que puede configurar argv[0]cualquier cosa cuando usted exec*()mismo programa. Es una convención del shell establecer argv[0]la ruta que se usó para iniciar el programa (y es aconsejable hacer lo mismo cuando exec*()un programa, ya que muchos programas inspeccionan argv[0]y esperan que mantenga la ruta).
Ulfalizer
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.