Comment trouver l'emplacement de l'exécutable en C? [dupliquer]
cette question a déjà une réponse ici:
y a-t-il un moyen en C/C++ de trouver l'emplacement (chemin complet) du programme courant exécuté?
(le problème avec argv[0]
est qu'il ne donne pas le chemin d'accès complet.)
9 réponses
pour résumer:
-
Sur Unix avec
/proc
vraiment simple et fiable moyen est de:-
readlink("/proc/self/exe", buf, bufsize)
(Linux) -
readlink("/proc/curproc/file", buf, bufsize)
(FreeBSD) -
readlink("/proc/self/path/a.out", buf, bufsize)
(Solaris)
-
-
sur Unixes sans
/proc
(c'est à dire si au-dessus échoue):-
Si argv[0] commence par "/" (chemin absolu) c'est le chemin.
-
dans les autres cas, si argv[0] contient "/" (trajectoire relative), l'ajouter à cwd (en supposant qu'elle n'ait pas encore été changée).
-
autrement rechercher des répertoires dans
$PATH
pour l'exécutableargv[0]
.
ensuite, il peut être raisonnable de vérifier si l'exécutable n'est pas réellement un lien symbolique. S'il est résolu par rapport au répertoire symlink.
cette étape n'est pas nécessaire dans la méthode /proc (au moins pour Linux). Là, le lien symbolique proc pointe directement vers l'exécutable.
notez qu'il appartient au processus d'appel de définir
argv[0]
correctement. Il est juste la plupart du temps, mais il ya des occasions où le processus d'appel ne peut pas être de confiance (ex. setuid exécutable). -
-
sur Windows: utilisez
GetModuleFileName(NULL, buf, bufsize)
Utiliser GetModuleFileName() fonction si vous utilisez Windows.
veuillez noter que les commentaires suivants sont unix-seulement.
la réponse pédante à cette question Est qu'il n'y a pas de général façon de répondre correctement à cette question dans tous les cas. Comme vous l'avez découvert, argv[0] peut être défini à n'importe quoi par le processus parent, et n'a donc absolument aucune relation avec le nom réel du programme ou son emplacement dans le système de fichiers.
cependant, les heuristiques suivantes souvent œuvres:
- si argv[0] est un chemin absolu, supposons que c'est le chemin complet de l'exécutable.
- si argv[0] est un chemin relatif, c'est-à-dire qu'il contient un
/
, déterminez le répertoire de travail courant avec getcwd() et ajoutez argv[0] à celui-ci. - si argv[0] est un mot simple, Cherchez $PATH à la recherche d'argv[0], et ajoutez argv[0] à n'importe quel répertoire où vous le trouverez.
Notez que tous ces éléments peuvent être contournées par le processus qui a invoqué le programme en question. Enfin, vous pouvez utiliser des techniques spécifiques à linux, comme celles mentionnées par emg-2. Il existe probablement des techniques équivalentes sur d'autres systèmes d'exploitation.
même en supposant que les étapes ci-dessus vous donnent un nom de chemin valide, vous pourriez ne pas avoir le nom de chemin que vous voulez réellement (puisque je soupçonne que ce que vous voulez réellement faire est de trouver un fichier de configuration quelque part). Présence de liens durs signifie que vous pouvez avoir la situation suivante:
-- 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
maintenant, l'approche ci-dessus (incluant, je soupçonne, /proc/$pid/exe) donnera /some/where/else/foo
comme véritable chemin vers le programme. Et, en fait, c'est un vrai chemin d'accès au programme, mais pas celui que vous vouliez. Notez que ce problème ne se produit pas avec les liens symboliques qui sont beaucoup plus communs dans la pratique que les liens durs.
malgré le fait que cette approche est en principe peu fiable, elle fonctionne assez bien dans la pratique pour la plupart des cas.
ce n'est pas une réponse en fait, mais juste une note à garder à l'esprit.
comme nous avons pu le voir, le problème de trouver l'emplacement de l'exécutable en cours d'exécution est assez délicat et spécifique à la plate-forme sous Linux et Unix. On devrait y réfléchir à deux fois avant de faire ça.
si vous avez besoin de votre emplacement exécutable pour découvrir des fichiers de configuration ou de ressources, peut-être devriez-vous suivre la méthode Unix pour placer des fichiers dans le système: mettez configs à /etc
ou /usr/local/etc
ou dans le répertoire courant de l'utilisateur, et /usr/share
est un bon endroit pour mettre vos fichiers de ressources.
dans de nombreux systèmes POSIX, vous pouvez vérifier un simlink situé sous /proc/PID/exe. Quelques exemples:
# 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
se rappeler que sur les systèmes Unix le binaire peut avoir été enlevé depuis qu'il a été commencé. C'est parfaitement légal et sécurisé sur Unix. Dernière, j'ai vérifié Windows ne vous permettra pas de supprimer l'exécution d'un binaire.
/proc/self / exe sera toujours lisible, mais ce ne sera pas vraiment un lien symbolique fonctionnel. Il sera... bizarre.
Pour Linux vous pouvez trouver la /proc/self/exe
façon de faire les choses emmitouflé dans une belle bibliothèque appelée binreloc, vous pouvez trouver la bibliothèque à:
sur Mac OS X, utiliser _NSGetExecutablePath
.
voir man 3 dyld
et cette réponse à une question similaire.
je
1) utiliser la fonction basename (): http://linux.die.net/man/3/basename
2) chdir() vers le répertoire
3) Utilisez getpwd () pour obtenir le répertoire courant
de cette façon, vous obtiendrez le répertoire dans une forme soignée, complète, au lieu de ./ ou. ./bac./
peut-être que vous voudrez sauvegarder et restaurer le répertoire courant, si cela est important pour votre programme.