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