Linux Notizen / Programm Pfad
 
StartSeite | LinuxNotizen/ | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

Unter Unix / Linux ist es viele ungewöhnlicher, den Pfad des exekutierenden Programmes ermitteln zu wollen.

Ein Snippet, das Olaf Rogalski (ohne Gewähr) dazu teilt:

#include <stdio.h>
#include <unistd.h>

char* getexecpath() {
  static char buf[30], execpath[2048];

  sprintf(buf,"/proc/%d/exe", getpid()); /* [1] Linux */
  /* sprintf(buf,"/proc/%d/file", getpid()); /* [2] FreeBSD (Ergänzung -- hl) */
  memset(execpath, 0, sizeof(execpath));
  readlink(buf, execpath, sizeof(execpath));
  return execpath;
}

int main(int argc, char *argv[]) {
  printf("execpath: %s\n", getexecpath());
  remove(getexecpath()); /* [3] */
  printf("execpath: %s\n", getexecpath()); /* [4] */
  return 0;
}

Diskussion

Ich verstehe nicht, was die Codezeilen [3]/[4] demonstrieren sollen. Ein Kommentar wäre gut. -- vgl

Mmmh, ich glaube, das ist ein Nebengedanke zur Selbstlöschung eines exekutierenden Exes (unter Windows nur über Klimmzüge möglich). Unter Unix scheint das möglich zu sein. -- HelmutLeitner

Das eigentliche Problem mit dem Programmpfad in Unix liegt m. E. darin, dass er nicht eindeutig zu sein braucht, da dasselbe Programm-File als Hard-Link in verschiedenen Directories stehen kann und man dann also nicht sagen kann, welches davon das "eigentliche" Installations-Directory des Programms ist (in dem man dann zur Laufzeit z. B. nach weiteren für den Programmablauf wichtigen Files suchen würde). Der obige "readlink"-Aufruf liefert ja nur denjenigen Pfadnamen, über den das Programm gestartet wurde; dieser muss nicht in das "wahre" Installationsverzeichnis zeigen. Will man letzteres zur Laufzeit feststellen können, so bleibt wohl i. a. nichts übrig, als zur Installationszeit an einem festen Ort in der Verzeichnis-Struktur eine entsprechende Konfigurations-Beschreibungs-Datei zu hinterlegen. -- kg

Das ist eine Unix-Denkweise, die aber am Kern dessen vorbeigeht, was man üblicherweise mit dem Programmpfad tun will (am selben Pfad einen Konfigurationsfile zu erreichen). Dabei ist es unerheblich, ob dieser Pfad zwischen Aufrufen stabil ist oder eindeutig ist. Z. B. ist auf diese Weise die Installation und der Betrieb verschiedener Programmversionen nebeneinander problemlos möglich ohne dass sich die Konfigurationsinformationen in die Quere kommen. -- HelmutLeitner

Das ist keine Unix-Denkweise. Das ist eine DOS-Denkweise. In Unix-Systemen gibt es wohldefinierte Orte in der VerzeichnisHierarchie?, an denen globale und userspezifische Konfigurationsdateien zu finden sind. Mit Softwarepaketen aktuellen Standes läßt sich das beim
configure
Aufruf angeben, für viele Anwendungen genügt es jedoch auf der Kommandozeile alternative Konfigurationsdateien anzugeben.

Ich wollte ja auch nur sagen, dass es den Programmpfad in Unix streng genommen eigentlich nicht gibt. Das ist wahrscheinlich der Grund dafür, dass es in Unix keinen Standard-Aufruf zur Bestimmung "des" Programmpfades gibt, sondern man solche (nicht-portablen) Tricks wie im Kasten oben anwenden muss. Man kann jedoch damit leben, wenn man entweder wie oben von mir beschrieben verfährt, oder die Programm-Installierer davor warnt, das Programm über einen Hard-Link zu starten, der außerhalb des Installationsverzeichnisses angesiedelt ist.

Symbolic Links sind hingegen kein Problem und werden sehr häufig auch schon bei der Installation von Software eingerichtet, um die neueste Version der Software in einem Verzeichnis (wie /bin, /usr/bin, /usr/local/bin) bereitzustellen, das üblicherweise im PATH liegt, und zwar entweder unter einem versionsspezifischen Namen, oder unter einem immer gleichen Namen, der der jeweils aktuellen, neuesten Version vorbehalten ist.

Ergänzung: In dem aktuellen Release 3.2.x des plattform-übergreifenden Qt Toolkits gibt es in der QApplication-Klasse zwei Methoden "applicationDirPath()" und "applicationFilePath()" für die Bestimmung des Installations-Verzeichnisses und des Programmpfades. Unter UNIX liefern sie unter den folgenden Voraussetzungen den korrekten Installations-Pfad:

  1. Das Programm wird nicht über einen Hard Link aus einem anderen als dem Installations-Verzeichnis gestartet.
  2. Wenn es über einen relativen Pfadnamen gestartet wird, dann ändert das Programm das Current Working Directory bis zum Aufruf dieser Methoden nicht.
  3. Wenn das Programm über die Umgebungsvariable "PATH" gefunden wird, dann liefert diese das wahre Installationsverzeichnis des Programms. --kg
Kann jemand mal eine Programm-Ausgabe von unter Linux oder FreeBSD präsentieren? Was liefert denn die zweite Ausgabe? (Habe hier nur Solaris, da funktioniert keine der beiden Varianten, es gibt weder "exe" noch "file" unterhalb von "/proc/.../"). -- vgl

Wie schaut denn unter Solaris das /proc/.../ Verzeichnis aus. Gibt es den Programmpfad unter einem anderen Namen? -- HelmutLeitner

/proc/.../ Verzeichnis unter Solaris (SunOS 5.8)

/home/[...] > ps | grep $$   
 26895 pts/38   0:02 ksh

/home/[...] > ls -alF /proc/$$
[...]
dr-x--x--x  [...]     736 May 13 08:02 ./
dr-xr-xr-x  [...]  480032 May 13 15:15 ../
-rw-------  [...] 2031616 May 13 08:02 as
-r--------  [...]     152 May 13 08:02 auxv
-r--------  [...]      56 May 13 08:02 cred
--w-------  [...]       0 May 13 08:02 ctl
lr-x------  [...]       0 May 13 08:02 cwd -> /
dr-x------  [...]    2064 May 13 08:02 fd/
-r--r--r--  [...]     120 May 13 08:02 lpsinfo
-r--------  [...]     912 May 13 08:02 lstatus
-r--r--r--  [...]     536 May 13 08:02 lusage
dr-xr-xr-x  [...]      48 May 13 08:02 lwp/
-r--------  [...]    2016 May 13 08:02 map
dr-x------  [...]     544 May 13 08:02 object/
-r--------  [...]    2384 May 13 08:02 pagedata
-r--r--r--  [...]     336 May 13 08:02 psinfo
-r--------  [...]    2016 May 13 08:02 rmap
lr-x------  [...]       0 May 13 08:02 root -> /
-r--------  [...]    1440 May 13 08:02 sigact
-r--------  [...]    1232 May 13 08:02 status
-r--r--r--  [...]     256 May 13 08:02 usage
-r--------  [...]       0 May 13 08:02 watch
-r--------  [...]    3192 May 13 08:02 xmap

SuSE Linux (8.0)

leitner@linux:~/c/test> cat epath.c
#include <stdio.h>
#include <unistd.h>
 
char* getexecpath() {
  static char buf[30], execpath[2048];
 
  sprintf(buf,"/proc/%d/exe", getpid());
  memset(execpath, 0, sizeof(execpath));
  readlink(buf, execpath, sizeof(execpath));
  return execpath;
}
                                                                               
int main(int argc, char *argv[]) {  
  printf("execpath: %s\n", getexecpath());
  remove(getexecpath());
  printf("execpath: %s\n", getexecpath());
  return 0;
}
 
leitner@linux:~/c/test> gcc epath.c
leitner@linux:~/c/test> a.out  
execpath: /home/leitner/c/test/a.out
execpath: /home/leitner/c/test/a.out (deleted)
leitner@linux:~/c/test> ll /proc/$$
total 0
dr-xr-xr-x    3 leitner  nogroup         0 May 13 22:09 .
dr-xr-xr-x   55 root     root            0 May  8 17:45 ..
-r--r--r--    1 leitner  nogroup         0 May 13 22:09 cmdline
lrwxrwxrwx    1 leitner  nogroup         0 May 13 22:09 cwd -> /home/leitner/c/test
-r--¦---¦---    1 leitner  nogroup         0 May 13 22:09 environ
lrwxrwxrwx    1 leitner  nogroup         0 May 13 22:09 exe -> /bin/bash
dr-x-¦---¦--    2 leitner  nogroup         0 May 13 22:09 fd
-r--r--r--    1 leitner  nogroup         0 May 13 22:09 maps
-rw--¦---¦--    1 leitner  nogroup         0 May 13 22:09 mem
lrwxrwxrwx    1 leitner  nogroup         0 May 13 22:09 root -> /
-r--r--r--    1 leitner  nogroup         0 May 13 22:09 stat
-r--r--r--    1 leitner  nogroup         0 May 13 22:09 statm
-r--r--r--    1 leitner  nogroup         0 May 13 22:09 status
leitner@linux:~/c/test> 

FreeBSD (4.4)

wikise /usr/home/wikise/c/test% cat epath.c
#include <stdio.h>
#include <unistd.h>

char* getexecpath() {
  static char buf[30], execpath[2048];

//  sprintf(buf,"/proc/%d/exe", getpid());
  sprintf(buf,"/proc/%d/file", getpid());
  memset(execpath, 0, sizeof(execpath));
  readlink(buf, execpath, sizeof(execpath));
  return execpath;
}

int main(int argc, char *argv[]) {
  printf("execpath: %s\n", getexecpath());
  remove(getexecpath());
  printf("execpath: %s\n", getexecpath());
  return 0;
}

wikise /usr/home/wikise/c/test% gcc epath.c
wikise /usr/home/wikise/c/test% a.out
execpath: /usr/home/wikise/c/test/a.out
execpath: unknown
wikise /usr/home/wikise/c/test% ll /proc/$$
total 0
-r--r--r--  1 wikise  vuser    0 13 Mai 21:16 cmdline
--w---¦--¦--  1 wikise  vuser    0 13 Mai 21:16 ctl
-rw--¦--¦---  1 wikise  vuser   32 13 Mai 21:16 dbregs
-r--r--r--  1 wikise  vuser    0 13 Mai 21:16 etype
lr-xr-xr-x  1 wikise  vuser    9 13 Mai 21:16 file -> /bin/tcsh
-rw--¦---¦--  1 wikise  vuser  176 13 Mai 21:16 fpregs
-r--r--r--  1 wikise  vuser    0 13 Mai 21:16 map
-rw-r--¦---  1 wikise  vuser    0 13 Mai 21:16 mem
--w---¦--¦--  1 wikise  vuser    0 13 Mai 21:16 note
--w--¦--¦---  1 wikise  vuser    0 13 Mai 21:16 notepg
-rw--¦--¦---  1 wikise  vuser   76 13 Mai 21:16 regs
-r--r--r--  1 wikise  vuser    0 13 Mai 21:16 rlimit
-r--r--r--  1 wikise  vuser    0 13 Mai 21:16 status


KategorieUnix KategorieLinux KategorieSnippet
StartSeite | LinuxNotizen/ | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 9. September 2003 11:52 (diff))
Suchbegriff: gesucht wird
im Titel
im Text