2009-06-01 14 views
131

¿Hay alguna forma en C/C++ para encontrar la ubicación (ruta completa) del programa ejecutado actualmente?¿Cómo puedo encontrar la ubicación del ejecutable en C?

(El problema con argv[0] es que no da la ruta completa.)

+11

cual sistema operativo? –

+6

Buena respuesta aquí también: http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe/1024937#1024937 – ergosys

+0

Esta pregunta ("¿Cómo puedo encontrar la ubicación de mi programa en SETTING X? ") podría * realmente * usar una etiqueta; ¡es difícil buscar usando palabras clave! – SamB

Respuesta

178

En resumen:

  • En Unix con /proc muy recta y forma realiable es:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

  • En Unixes sin /proc (es decir, si falla arriba):

    • Si argv [0] comienza con "/" (ruta absoluta) esta es la ruta.

    • De lo contrario, si argv [0] contiene "/" (ruta relativa), agréguela a cwd (suponiendo que no se haya cambiado aún).

    • De lo contrario, directorios de búsqueda en $PATH para ejecutable argv[0].

    Posteriormente, puede ser razonable comprobar si el archivo ejecutable no es realmente un enlace simbólico. Si se resuelve en relación con el directorio de enlace simbólico.

    Este paso no es necesario en el método/proc (al menos para Linux). Allí, el enlace simbólico proc apunta directamente al ejecutable.

    Tenga en cuenta que corresponde al proceso de llamada establecer argv[0] correctamente. Es correcto la mayoría de las veces, sin embargo, hay ocasiones en que no se puede confiar en el proceso de llamada (por ejemplo, ejecutable de setuid).

  • En Windows: El uso GetModuleFileName(NULL, buf, bufsize)

+0

+1 nice sharp answer –

+20

Cualquier cosa que dependa de que argv [0] sea el nombre del programa no es confiable. Funcionará la mayor parte del tiempo, pero no * cada * vez. Este problema es difícil en unixes sin/proc – dmckee

+7

No todas las unixes con proc tienen/proc/self/exe. El diseño de/proc es completamente específico del sistema operativo y todos lo hacen de forma un poco diferente. Por ejemplo, FreeBSD proporciona/proc/curproc/file que funciona igual que Linux/proc/self/exe. Pero otros pueden no hacer esto en absoluto. – MarkR

6

En muchos sistemas POSIX se puede comprobar una simlink encuentra bajo/proc/PID/exe. Algunos ejemplos:

# file /proc/*/exe 
/proc/1001/exe: symbolic link to /usr/bin/distccd 
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail 
/proc/1043/exe: symbolic link to /usr/sbin/crond 
+11

/proc no es POSIX, y no está muy estandarizado. Muchos Unices modernos lo tienen, otros no. –

+0

Siempre es bueno aprender cosas nuevas. Gracias. ¿Hay más forma "programática" de hacer esto? – eran

+0

@Dietrich: tienes razón, no es posix. Según Wikipedia, los sistemas de tipo unix que lo tienen son: Linux, AIX, BSD, Solaris, QNX. Sin embargo, no se indica si todos esos sistemas tienen/proc/*/cmd simlink. –

17

Utilice la función GetModuleFileName() si está utilizando Windows.

+2

Gracias, pero estoy usando linux y unix. – eran

15

Tenga en cuenta que los siguientes comentarios son solo de Unix.

La pedante respuesta a esta pregunta es que no hay general manera de responder esta pregunta correctamente en todos los casos. Como ha descubierto, argv [0] se puede establecer en todo por el proceso principal, por lo que no debe tener relación alguna con el nombre real del programa o su ubicación en el sistema de archivos.

Sin embargo, la siguiente heurística menudo funciona:

  1. Si argv [0] es una ruta absoluta, supongo que es la ruta completa al ejecutable.
  2. Si argv [0] es una ruta relativa, es decir, contiene un /, determine el directorio de trabajo actual con getcwd() y añádale argv [0].
  3. Si argv [0] es una palabra llana, búsqueda $ PATH en busca de argv [0], y anexar argv [0] para el directorio que lo encuentras en.

Tenga en cuenta que todos estos pueden ser eludido por el proceso que invocó el programa en cuestión. Finalmente, puede usar técnicas específicas de Linux, como las mencionadas por emg-2. Probablemente haya técnicas equivalentes en otros sistemas operativos.

Incluso suponiendo que los pasos anteriores le den un nombre de ruta válido, puede que aún no tenga la ruta que realmente desea (ya que sospecho que lo que realmente desea hacer es encontrar un archivo de configuración en alguna parte). La presencia de enlaces duros significa que usted puede tener la siguiente situación:

-- assume /app/bin/foo is the actual program 
$ mkdir /some/where/else 
$ ln /app/bin/foo /some/where/else/foo  # create a hard link to foo 
$ /some/where/else/foo 

Ahora, el enfoque anterior (incluyendo, sospecho,/proc/$ pid/exe) dará /some/where/else/foo como el camino real para el programa . Y, de hecho, es un camino real al programa, simplemente no el que usted quería. Tenga en cuenta que este problema no ocurre con enlaces simbólicos que son mucho más comunes en la práctica que los enlaces duros.

A pesar de que este enfoque es, en principio, poco confiable, funciona bastante bien en la práctica para la mayoría de los propósitos.

3

Hay que recordar que en los sistemas Unix el binario puede haber sido eliminado desde que se inició. Es perfectamente legal y seguro en Unix. La última vez que verifiqué, Windows no le permitirá eliminar un binario en ejecución.

/proc/self/exe seguirá siendo legible, pero realmente no será un enlace simbólico activo. Será ... extraño.

+0

¿Unix carga todo el programa ejecutable en la memoria antes de ejecutar? En ese caso, ¿cómo puede tener suficiente memoria para ejecutar programas muy grandes, como algunos archivos autoextraíbles? –

+1

Generalmente no. El ejecutable está bloqueado (intentar abrir para escribir da "archivo de texto ocupado") y "memoria asignada", lo que significa que * parece * como que todo está en la memoria, pero se cargará de forma lenta la primera vez que se acceda a una página de memoria. Si se trata de una página de solo lectura (como suele ser el código), el kernel puede "olvidar" los datos si necesita la memoria y volver a cargarlos cuando vuelva a acceder a ellos. Más o menos como el intercambio, pero como el código no se modifica, nunca se volverá a escribir en el disco. – Thomas

+0

Supongo que en ese caso si la página de memoria descargada se carga en la memoria después de que se haya eliminado el archivo, pasará algo grave –

9

No es una respuesta en realidad, sino solo una nota a tener en cuenta.

Como pudimos ver, el problema de encontrar la ubicación del ejecutable en ejecución es bastante complicado y específico de la plataforma en Linux y Unix. Uno debería pensar dos veces antes de hacer eso.

Si necesita su ubicación ejecutable para descubrir algunos archivos de configuración o de recursos, tal vez debería seguir el camino de Unix de colocar los archivos en el sistema: poner configuraciones de /etc o /usr/local/etc o en el directorio personal del usuario actual, y /usr/share es un buen lugar para poner sus archivos de recursos.

0

Me

1) Utilizar la función nombre base(): http://linux.die.net/man/3/basename
2) chdir() para ese directorio
3) Utilice getpwd() para obtener el directorio actual

De esa manera usted Obtendré el directorio en forma ordenada y completa, en lugar de ./ o ../bin/.

Quizás desee guardar y restaurar el directorio actual, si eso es importante para su programa.

3

Para Linux se puede encontrar la manera de hacer las cosas envuelto en una bonita biblioteca llamada binreloc /proc/self/exe, se puede encontrar la biblioteca en:

+0

+1 para la biblioteca BinReloc. –

+1

enlace está muerto. :( –

Cuestiones relacionadas