Re: [AD] Using procfs on UNIX for get_executable_name |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
On Friday 06 August 2004 16:08, Evert Glebbeek wrote:
> The attached patch changes get_executable_name on UNIX platforms to use
> procfs if this is available.
I'm going to apply the attached (more or less equivalent) patch. The only
difference is that it will use __crt0_argv[0] as a last resort if all else
fails.
I'll be making a patch to remove END_OF_MAIN() and with it __crt0_argv on
UNIX systems later on, if we still want that.
Evert
Index: aclocal.m4
===================================================================
RCS file: /cvsroot/alleg/allegro/aclocal.m4,v
retrieving revision 1.65
diff -u -r1.65 aclocal.m4
--- aclocal.m4 6 Aug 2004 15:07:24 -0000 1.65
+++ aclocal.m4 17 Aug 2004 19:25:19 -0000
@@ -178,6 +178,31 @@
])
dnl
+dnl Test for System V sys/procfs.h.
+dnl
+dnl Variables:
+dnl allegro_sv_procfs=(yes|no)
+dnl
+AC_MSG_CHECKING(for System V sys/procfs)
+AC_DEFUN(ALLEGRO_SV_PROCFS,
+[AC_CHECK_HEADER(sys/procfs.h,
+AC_TRY_COMPILE([#include <sys/procfs.h>], [struct prpsinfo psinfo;],
+allegro_sv_procfs=yes, allegro_sv_procfs=no), allegro_sv_procfs=no)])
+AC_MSG_RESULT($allegro_sv_procfs)
+
+dnl
+dnl Test if sys/procfs.h tells us argc/argv.
+dnl
+dnl Variables:
+dnl allegro_procfs_argcv=(yes|no)
+dnl
+AC_MSG_CHECKING(if sys/procfs.h tells us argc/argv)
+AC_DEFUN(ALLEGRO_PROCFS_ARGCV,
+[AC_TRY_COMPILE([#include <sys/procfs.h>], [struct prpsinfo psinfo; psinfo.pr_argc = 0;],
+allegro_procfs_argcv=yes, allegro_procfs_argcv=no)])
+AC_MSG_RESULT($allegro_procfs_argcv)
+
+dnl
dnl Test for X-Windows support.
dnl
dnl Variables:
Index: configure.in
===================================================================
RCS file: /cvsroot/alleg/allegro/configure.in,v
retrieving revision 1.81
diff -u -r1.81 configure.in
--- configure.in 13 Aug 2004 08:18:40 -0000 1.81
+++ configure.in 17 Aug 2004 19:25:20 -0000
@@ -414,6 +414,19 @@
_disabled_modules="ossmidi $_disabled_modules"
fi
+dnl Test for System V procfs
+ALLEGRO_SV_PROCFS
+if test "$allegro_sv_procfs" = yes; then
+ AC_DEFINE(ALLEGRO_HAVE_SV_PROCFS,1,
+ [Define to 1 if you have a System V sys/procfs.h])
+
+ ALLEGRO_PROCFS_ARGCV
+ if test "$allegro_procfs_argcv" = yes; then
+ AC_DEFINE(ALLEGRO_HAVE_PROCFS_ARGCV,1,
+ [Define to 1 if procfs reveals argc and argv])
+ fi
+fi
+
dnl Test for X-Windows support.
ALLEGRO_ACTEST_SUPPORT_XWINDOWS
if test "$allegro_support_xwindows" = yes; then
Index: src/unix/usystem.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/unix/usystem.c,v
retrieving revision 1.30
diff -u -r1.30 usystem.c
--- src/unix/usystem.c 6 Aug 2004 15:15:30 -0000 1.30
+++ src/unix/usystem.c 17 Aug 2004 19:25:21 -0000
@@ -41,6 +41,9 @@
#include <sys/utsname.h>
#endif
+#ifdef ALLEGRO_HAVE_SV_PROCFS
+ #include <sys/procfs.h>
+#endif
/* list the available drivers */
@@ -240,38 +243,40 @@
#ifndef ALLEGRO_MACOSX
-
-/* _unix_get_executable_name:
- * Return full path to the current executable.
+/* _find_executable_file:
+ * Helper function: searches path and current directory for executable.
+ * Returns 1 on succes, 0 on failure.
*/
-void _unix_get_executable_name(char *output, int size)
+static int _find_executable_file(const char *filename, char *output, int size)
{
- FILE *pipe;
- char linkname[1024];
- char filename[1024];
- struct stat buf;
char *path;
- 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;
+ /* 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 1;
+ }
+ else {
+ struct stat finfo;
+ char pathname[1024];
+ int len;
+
+ /* Prepend current directory */
+ getcwd(pathname, sizeof(pathname));
+ len = strlen(pathname);
+ pathname[len] = '/';
+ _al_sane_strncpy (pathname+len+1, filename, strlen(filename));
+
+ if ((stat(pathname, &finfo)==0) && (!S_ISDIR (finfo.st_mode))) {
+ do_uconvert (pathname, U_ASCII, output, U_CURRENT, size);
+ return 1;
+ }
}
}
-
- /* Cannot stat /proc/pid/exe, or cannot resolve symlink. */
- /* Fall back on the old argv[0] method */
- /* If argv[0] has no explicit path, but we do have $PATH, search there */
- if (!strchr (__crt0_argv[0], '/') && (path = getenv("PATH"))) {
+ /* 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;
@@ -279,19 +284,19 @@
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);
+ /* 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, __crt0_argv[0], end - start + 1 + strlen (__crt0_argv[0]) + 1);
+ _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;
+ return 1;
}
} /* else... ignore the failure; `buffer' is still valid anyway. */
@@ -300,9 +305,117 @@
/* Path search failed */
free (buffer);
}
+
+ return 0;
+}
+
+/* _unix_get_executable_name:
+ * Return full path to the current executable, use proc fs if available.
+ */
+void _unix_get_executable_name(char *output, int size)
+{
+ #ifdef ALLEGRO_HAVE_SV_PROCFS
+ struct prpsinfo psinfo;
+ int fd;
+ char *s;
+ #endif
+ char linkname[1024];
+ char filename[1024];
+ struct stat finfo;
+ FILE *pipe;
+ pid_t pid;
+ int len;
+
+ /* We need the PID in order to query procfs */
+ pid = getpid();
+
+ /* First try a Linux-like procfs */
+ /* get symolic link to executable from proc fs */
+ sprintf (linkname, "/proc/%d/exe", pid);
+ if (stat (linkname, &finfo) == 0) {
+ len = readlink (linkname, filename, sizeof(filename)-1);
+ if (len>-1) {
+ filename[len] = '\0';
+
+ do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+ return;
+ }
+ }
+
+ /* Use System V procfs calls if available */
+ #ifdef ALLEGRO_HAVE_SV_PROCFS
+ sprintf (linkname, "/proc/%d/exe", pid);
+ fd = open(linkname, O_RDONLY);
+ ioctl(fd, PIOCPSINFO, &psinfo);
+ close(fd);
+
+ /* Use argv[0] directly if we can */
+ #ifdef ALLEGRO_HAVE_PROCFS_ARGCV
+ if (_find_executable_file(psinfo.pr_argv[0], output, size))
+ return;
+ #else
+ /* Emulate it */
+ /* We use the pr_psargs field to find argv[0]
+ * This is better than using the pr_fname field because we need the
+ * additional path information that may be present in argv[0]
+ */
+
+ /* Skip other args */
+ s = strchr(psinfo.pr_psargs, ' ');
+ if (s) s[0] = '\0';
+ if (_find_executable_file(psinfo.pr_psargs, output, size))
+ return;
+ #endif
+
+ /* Try the pr_fname just for completeness' sake if argv[0] fails */
+ if (_find_executable_file(psinfo.pr_fname, output, size))
+ return;
+ #endif
+
+ /* Last resort: 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);
+
+ if (_find_executable_file(filename, output, size))
+ return;
+
+ /* Just return the output from ps... */
+ do_uconvert (filename, U_ASCII, output, U_CURRENT, size);
+ return;
+ }
+
+ /* Try the captured argv[0] */
+ if (_find_executable_file(__crt0_argv[0], output, size))
+ return;
- /* 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);
+ /* Give up; return empty string */
+ do_uconvert ("", U_ASCII, output, U_CURRENT, size);
}
#endif