Re: [AD] No more END_OF_MAIN on *nix!

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On Monday 02 August 2004 09:47, Evert Glebbeek wrote:
> What could work is find the last column by starting right in the first 
> output and walk backwards, as I now do for the second line of output. I'm 
> going to look into that.
[...]
> > The square brackets are disturbing. 
> 
> Yes. Possibly something that we could detect though...
[...] 
> > Further, if you run ps -f on a login
> > shell, you get an extra dash for free:
> 
> Yeah, I saw that too. I figured it wouldn't be a real problem if Allegro 
> programs are not run as a login shell. Worst case, we could detect that 
> too.

Ok, revised patch attached. The only thing missing as far as I'm concerned 
is that we could call canonicalize_filename() somewhere in order to 
eliminate sillyness such as /home/user/somedir/some_other_dir/../../
somedir/myprogram, but that is mostly a cosmetic issue.

At any rate, I'm going to apply the procfs portion to mainline and add a 
note in the docs that if a Linux-like procfs is not available, then the 
output from get_executable_filename can be unreliable.

Evert
--- allegro/src/unix/usystem.c	2004-07-28 19:56:56.000000000 +0200
+++ alleg_no_magic_main/src/unix/usystem.c	2004-08-02 13:19:08.000000000 +0200
@@ -16,6 +16,7 @@
  */
 
 
+#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -240,45 +241,124 @@
 #ifndef ALLEGRO_MACOSX
 
 /* _unix_get_executable_name:
- *  Return full path to the current executable.
+ *  Return full path to the current executable, use proc fs if available.
  */
 void _unix_get_executable_name(char *output, int size)
 {
+   FILE *pipe;
+   char linkname[1024];
+   char filename[1024];
+   struct stat buf;
    char *path;
-
-   /* If argv[0] has no explicit path, but we do have $PATH, search there */
-   if (!strchr (__crt0_argv[0], '/') && (path = getenv("PATH"))) {
-      char *start = path, *end = path, *buffer = NULL, *temp;
-      struct stat finfo;
-
-      while (*end) {
-	 end = strchr (start, ':');
-	 if (!end) end = strchr (start, '\0');
-
-	 /* Resize `buffer' for path component, slash, argv[0] and a '\0' */
-	 temp = realloc (buffer, end - start + 1 + strlen (__crt0_argv[0]) + 1);
-	 if (temp) {
-	    buffer = temp;
-
-	    _al_sane_strncpy (buffer, start, end - start);
-	    *(buffer + (end - start)) = '/';
-	    _al_sane_strncpy (buffer + (end - start) + 1, __crt0_argv[0], end - start + 1 + strlen (__crt0_argv[0]) + 1);
-
-	    if ((stat(buffer, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
-	       do_uconvert (buffer, U_ASCII, output, U_CURRENT, size);
-	       free (buffer);
-	       return;
-	    }
-	 } /* else... ignore the failure; `buffer' is still valid anyway. */
-
-	 start = end + 1;
+   pid_t pid;
+   int len;
+   
+   /* get symolic link to executable from proc fs */
+   pid = getpid();
+   sprintf (linkname, "/proc/%d/exe", pid);
+   
+   if (stat (linkname, &buf) == 0) {
+      len = readlink (linkname, filename, sizeof(filename)-1);
+      if (len>-1) {
+	 filename[len] = '\0';
+         
+	 do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+	 return;
       }
-      /* Path search failed */
-      free (buffer);
    }
-
-   /* If argv[0] had a slash, or the path search failed, just return argv[0] */
-   do_uconvert (__crt0_argv[0], U_ASCII, output, U_CURRENT, size);
+   
+   /* Cannot stat /proc/pid/exe, or cannot resolve symlink */
+   /* Try using the output of the ps command to at least find the name of */
+   /* the file if not the full path */
+   uszprintf (linkname, sizeof(linkname), "ps -f -p %d", pid);
+   do_uconvert (linkname, U_CURRENT, filename, U_ASCII, size);
+   pipe = popen(filename, "r");
+   if (pipe) {
+      /* The first line of output is a header */
+      fgets(linkname, sizeof(linkname), pipe);
+      
+      /* The information we want is in the last column; find it */
+      len = strlen(linkname);
+      while (linkname[len] != ' ' && linkname[len] != '\t')
+         len--;
+      
+      /* The second line contains the info we want */
+      fgets(linkname, sizeof(linkname), pipe);
+      pclose(pipe);
+      
+      /* Treat special cases: filename between [] and - for login shell */
+      if (linkname[len] == '-')
+         len++;
+
+      if (linkname[len] == '[' && linkname[strlen(linkname)] == ']') {
+         len++;
+         linkname[strlen(linkname)] == '\0';
+      }         
+      
+      /* Now, the filename should be in the last column */
+      _al_sane_strncpy (filename, linkname+len+1, strlen(linkname)-len+1);
+            
+      do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+
+      /* If filename has an explicit path, search current directory */
+      if (strchr (filename, '/')) {
+         if (filename[0] == '/') {
+            /* Full path; done */
+            do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+            return;
+         }
+         else {
+            struct stat finfo;
+            
+            /* Prepend current directory */
+            getcwd(linkname, sizeof(linkname));
+            len = strlen(linkname);
+            linkname[len] = '/';
+            _al_sane_strncpy (linkname+len+1, filename, strlen(filename));
+            
+            if ((stat(linkname, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
+               do_uconvert (linkname, U_ASCII, output, U_CURRENT, size);
+               return;
+            }
+         }
+      }
+      /* If filename has no explicit path, but we do have $PATH, search there */
+      else if ((path = getenv("PATH"))) {
+         char *start = path, *end = path, *buffer = NULL, *temp;
+         struct stat finfo;
+
+         while (*end) {
+	    end = strchr (start, ':');
+	    if (!end) end = strchr (start, '\0');
+
+	    /* Resize `buffer' for path component, slash, filename and a '\0' */
+	    temp = realloc (buffer, end - start + 1 + strlen (filename) + 1);
+	    if (temp) {
+	       buffer = temp;
+
+	       _al_sane_strncpy (buffer, start, end - start);
+	       *(buffer + (end - start)) = '/';
+	       _al_sane_strncpy (buffer + (end - start) + 1, filename, end - start + 1 + strlen (filename) + 1);
+
+	       if ((stat(buffer, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
+	          do_uconvert (buffer, U_ASCII, output, U_CURRENT, size);
+	          free (buffer);
+	          return;
+	       }
+	    } /* else... ignore the failure; `buffer' is still valid anyway. */
+
+	    start = end + 1;
+         }
+         /* Path search failed */
+         free (buffer);
+      }
+      
+      do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+      return;
+   }
+   
+   /* Give up; return empty string */
+   do_uconvert ("", U_ASCII, output, U_CURRENT, size);
 }
 
 #endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/