significa - Recuperación programática de la ruta absoluta de una aplicación de línea de comandos de OS X
rutas absolutas y relativas linux (7)
En Linux, una aplicación puede obtener fácilmente su ruta absoluta consultando /proc/self/exe
. En FreeBSD, es más complicado, ya que tienes que crear una llamada a sysctl:
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
pero todavía es completamente factible. Sin embargo, no puedo encontrar una manera de determinar esto en OS X para una aplicación de línea de comandos. Si está ejecutando desde un paquete de aplicaciones, puede determinarlo ejecutando [[NSBundle mainBundle] bundlePath]
, pero como las aplicaciones de línea de comandos no están en paquetes, esto no ayuda.
(Nota: consultar argv[0]
no es una respuesta razonable, ya que, si se inicia desde un enlace simbólico, argv[0]
será ese enlace simbólico, no la ruta final al ejecutable llamado. argv[0]
también puede encontrarse si un La aplicación tonta usa una llamada exec()
y se olvida de inicializar argv correctamente, lo que he visto en la naturaleza.)
¿Por qué no simplemente realpath(argv[0], actualpath);
? Es cierto que realpath tiene algunos límites (documentados en la página del manual) pero maneja bien los enlaces simbólicos. Probado en FreeBSD y Linux
% ls -l foobar lrwxr-xr-x 1 bortzmeyer bortzmeyer 22 Apr 29 07:39 foobar -> /tmp/get-real-name-exe % ./foobar My real path: /tmp/get-real-name-exe
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
int
main(argc, argv)
int argc;
char **argv;
{
char actualpath[PATH_MAX + 1];
if (argc > 1) {
fprintf(stderr, "Usage: %s/n", argv[0]);
exit(1);
}
realpath(argv[0], actualpath);
fprintf(stdout, "My real path: %s/n", actualpath);
exit(0);
}
Si el programa se inicia a través de PATH, vea la solución de pixelbeat.
Creo que hay una solución mucho más elegante, que en realidad funciona para cualquier PID y también devuelve la ruta absoluta directamente:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
int main (int argc, char* argv[])
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
if ( ret <= 0 ) {
fprintf(stderr, "PID %d: proc_pidpath ();/n", pid);
fprintf(stderr, " %s/n", strerror(errno));
} else {
printf("proc %d: %s/n", pid, pathbuf);
}
return 0;
}
Esto es tarde, pero [[NSBundle mainBundle] executablePath]
funciona bien para programas de línea de comandos no empaquetados.
La función _NSGetExecutablePath
devolverá una ruta completa al ejecutable (GUI o no). La ruta puede contener enlaces simbólicos, " ..
", etc., pero la función realpath
se puede usar para limpiarlos si es necesario. Vea _NSGetExecutablePath para más información.
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
printf("executable path is %s/n", path);
else
printf("buffer too small; need size %u/n", size);
El secreto de esta función es que el kernel de Darwin coloca la ruta ejecutable en la pila del proceso inmediatamente después de la matriz envp
cuando crea el proceso. El editor de enlaces dinámicos dyld
esto en la inicialización y mantiene un puntero a él. Esta función utiliza ese puntero.
No hay una forma garantizada, creo. Si argv [0] es un enlace simbólico, entonces podría usar readlink (). Si el comando se ejecuta a través de $ PATH, entonces se podría probar: search (getenv ("PATH")), getenv ("_"), dladdr ()
Parece que la respuesta es que no puedes hacerlo:
Estoy tratando de lograr algo como la funcionalidad de lsof y reunir un montón de estadísticas e información sobre los procesos en ejecución. Si el lsof no fuera tan lento, estaría feliz de seguir adelante.
Si reimplementas lsof, encontrarás que es lento porque está haciendo mucho trabajo.
Supongo que no es realmente porque lsof es el modo de usuario, es más que tiene que escanear el espacio de direcciones de una tarea en busca de cosas respaldadas por un buscapersonas externo. ¿Hay alguna forma más rápida de hacer esto cuando estoy en el núcleo?
No. lsof no es estúpido; Está haciendo lo que tiene que hacer. Si solo desea un subconjunto de su funcionalidad, puede considerar comenzar con la fuente lsof (que está disponible) y recortarla para cumplir con sus requisitos.
Por curiosidad, ¿se usa
p_textvp
? Parece que está configurado para elp_textvp
los padres enkern_fork
(y luego se libera?) Pero no se toca en ninguna de las rutinas dekern_exec
.
p_textvp
no se utiliza. En Darwin, el proc no es la raíz del espacio de direcciones; la tarea es No hay un concepto de "vnode" para el espacio de direcciones de una tarea, ya que no necesariamente se rellena inicialmente al asignar uno.Si exec rellenara p_textvp, supondría que todos los procesos están respaldados por un vnode. Entonces los programadores supondrían que era posible obtener una ruta al vnode, y desde allí es un pequeño salto al supuesto de que la ruta actual al vnode es la ruta desde la que se lanzó, y que el procesamiento de texto en la cadena podría llevar al nombre del paquete de aplicación ... todo lo cual sería imposible de garantizar sin una sanción sustancial.
GetProcessBundleLocation parece funcionar.